table of contents...go basic knowledge go foundation control statements and functions struct...

148

Upload: others

Post on 30-Dec-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming
Page 2: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

1.1

1.2

1.2.1

1.2.2

1.3

1.3.1

1.3.2

1.3.3

1.3.4

1.3.5

1.3.6

1.3.7

1.4

1.4.1

1.4.2

1.5

1.5.1

1.5.2

1.5.3

1.5.4

1.6

1.6.1

1.6.2

1.7

1.7.1

1.8

1.9

1.10

1.11

1.12

TableofContentsIntroduction

InstallationandTools

Installation

Tools

Gobasicknowledge

Gofoundation

Controlstatementsandfunctions

struct

Object-oriented

interface

Concurrency

Summary

General

GoProgrammingBasics

WebProgrammingBasics

Implementation

Basicwebapplication

Designingourwebapp

DatabaseHandling

WebappExample

Formhandling

WorkingwithForms

UploadingFiles

Templates

BasicsofTemplates

UserAuthentication

WorkingwithFiles

Routing

Middleware

BuildinganAPI

2

Page 3: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

1.13Contributors

3

Page 4: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Aboutthebook

ThisbookwaswrittentoteachhowtodevelopwebapplicationsinGofornewbies.

Youwillcreateatodolistapplicationasyougoaheadinthebook.Thebookaimstoteachconceptsbasedonsimpleyetrealexamplesandnotsomedummyexamples.

ThereisacodesectionavailableintheGithubrepo.Ifyouarereadingsomewhereotherthangithub,here'sthelinktotheGithubRepo

ReadOnlineDownloadPDF

CodeThebookcomeswithcorrespondingcode,pleaseuseittounderstandthebookcompletely,thebookisjustplainoldtheoryifyoudonotcheckthecodeout.

ContributingIdon'tprofesstobeaGodofeitherGoorwebdevoranythingingeneral,andIdon'tclaimthatthisisthebestbookforlearninghowtobuildwebappplicationswithGo,butIdobelievethatgoodthingshappenwhenpeoplecollaborate,sopullrequestsarenotonlyappreciated,buttheyarewelcome.

Igotfeedbackfromareddituserthatmaybeitistooearlyformetostartwritingthisbook,decadesago,ayoungstudentfromtheUniversityofHelsinkihadanendlessdebatewithAndrewTannenbaumovercomp.minix,itwasaboutmonolithickernels,hadthestudentlistenedtoAndrewTannenbaum,theworldprobablywouldnothavehadLinux.Thisisthewholepointofopensourceprojects,alittleinitiativefromeveryonegoesalongway.

PhilosophyThroughthisbookwewanttoteachhowtodevelopwebapplicationsinGo.WeexpectthereadertoknowthebasicsofGobutweassumethereaderknowsnothingabouthowtowritewebapplicationsThebookshallcompriseofchapters,ifthetopicishugeanddoesn'tfitintoonechapter,thenwesplitintomultiplechapters,ifpossible.

Introduction

4

Page 5: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Eachchaptershouldbesplitintologicalpartsorsectionswithameaningfultitlewhich'llteachthereadersomething.EveryconceptshouldbeaccompaniedbytheGocode(ifthereisany),forsneakpeektypesectionswritetheGopseudocode,writingjustthenecessarypartsofthecodeandkeepingeverythingelse.Thecodeshouldn'tbemorethan80characterswidebecauseinthePDFversionsofthebookthecodeisinvisible.Brevityisthesoulofwit,sokeepthedescriptionassmallaspossible.Butthisdoesn'tmeanthatweshouldjustassumethatthereaderknowstheconceptandskipitinsuchcasesdoexplaintheconcept.Inthetodolistmanagerwhichwearecreating,we'llstrivetoimplementasmuchfunctionalityaspossibletogiveatasteofpracticalGoprogrammingtothereader,butweshouldmentionasanotetheotherway,supposeyoure-implementafunctionlikeParseGlobbylistingallhtmlfilesandusingParseFilestoparsethem,weshouldmentionaboutthefunctionParseGlobThemaintitleshouldhaveone#,sectionsshouldhave3#'snoteshouldhave6#'s(noteshouldhaveatitletoo)Multilinecodeshouldhavethreetabsindentation,singlelineofcodecanbeindentedusingtabsorbybackticks.

WrittenwithloveinIndia.

License:BookLicense:CCBY-SA3.0License

Note:1. TheGoProgrammingBasicssectionhasbeenadaptedfrombuild-web-application-with-

golangbyastaxieLinkswereupdatedtoreferthecorrectaspectsofthecurrentbook,titleswereupdatedtofitintothisbook.

2. Thegopherinthecoverpageistakenfromhttps://golang.org/doc/gopher/appenginegophercolor.jpgwithoutmodifications.

LinksNextsection:InstallationandTools

Introduction

5

Page 6: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Introduction

6

Page 7: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

InstallationIfyouknowaboutinstallationorhaveinstalledGo,youcanskiptoTools.

Thischapteristakenfrominstallpageverbatim,exceptforthechangestobemadetoadapttothisbook'sstylingformat.

Systemrequirements

Gobinarydistributionsareavailableforthesesupportedoperatingsystemsandarchitectures.Pleaseensureyoursystemmeetstheserequirementsbeforeproceeding.IfyourOSorarchitectureisnotonthelist,youmaybeabletoinstallfromsourceorusegccgoinstead

Operatingsystem Architectures Notes

FreeBSD8-STABLEorlater amd64 DebianGNU/kFreeBSDnotsupported

Linux2.6.23orlaterwithglibc

amd64,386,arm

CentOS/RHEL5.xnotsupported;installfromsourceforARM

MacOSX10.7orlater amd64 usetheclangorgcc†thatcomeswith

Xcode‡

WindowsXPorlater amd64,386 useMinGWgcc†.Noneedforcygwinormsys

†gccisrequiredonlyifyouplantousecgo.

‡YouonlyneedtoinstallthecommandlinetoolsforXcode.IfyouhavealreadyinstalledXcode4.3+,youcaninstallitfromtheComponentstaboftheDownloadspreferencespanel.

InstalltheGotoolsIfyouareupgradingfromanolderversionofGoyoumustfirstremovetheexistingversion.Linux,MacOSX,andFreeBSDtarballs

Downloadthearchiveandextractitinto/usr/local,creatingaGotreein/usr/local/go.Forexample:

tar-C/usr/local-xzfgo$VERSION.$OS-$ARCH.tar.gz

InstallationandTools

7

Page 8: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Choosethearchivefileappropriateforyourinstallation.Forinstance,ifyouareinstallingGoversion1.2.1for64-bitx86onLinux,thearchiveyouwantiscalledgo1.2.1.linux-amd64.tar.gz.

(Typicallythesecommandsmustberunasrootorthroughsudo.)

Add/usr/local/go/bintothePATHenvironmentvariable.Youcandothisbyaddingthislinetoyour/etc/profile(forasystem-wideinstallation)or$HOME/.profile:

exportPATH=$PATH:/usr/local/go/bin

Installingtoacustomlocation

TheGobinarydistributionsassumetheywillbeinstalledin/usr/local/go(orc:\GounderWindows),butitispossibletoinstalltheGotoolstoadifferentlocation.InthiscaseyoumustsettheGOROOTenvironmentvariabletopointtothedirectoryinwhichitwasinstalled.

Forexample,ifyouinstalledGotoyourhomedirectoryyoushouldaddthefollowingcommandsto$HOME/.profile:

exportGOROOT=$HOME/go

exportPATH=$PATH:$GOROOT/bin

Note:GOROOTmustbesetonlywheninstallingtoacustomlocation.

MacOSXpackageinstaller

Downloadthepackagefile,openit,andfollowthepromptstoinstalltheGotools.ThepackageinstallstheGodistributionto/usr/local/go.

Thepackageshouldputthe/usr/local/go/bindirectoryinyourPATHenvironmentvariable.YoumayneedtorestartanyopenTerminalsessionsforthechangetotakeeffect.Windows

TheGoprojectprovidestwoinstallationoptionsforWindowsusers(besidesinstallingfromsource):aziparchivethatrequiresyoutosetsomeenvironmentvariablesandanMSIinstallerthatconfiguresyourinstallationautomatically.MSIinstaller

OpentheMSIfileandfollowthepromptstoinstalltheGotools.Bydefault,theinstallerputstheGodistributioninc:\Go.

Theinstallershouldputthec:\Go\bindirectoryinyourPATHenvironmentvariable.Youmayneedtorestartanyopencommandpromptsforthechangetotakeeffect.Ziparchive

Downloadthezipfileandextractitintothedirectoryofyourchoice(wesuggestc:\Go).

InstallationandTools

8

Page 9: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Ifyouchoseadirectoryotherthanc:\Go,youmustsettheGOROOTenvironmentvariabletoyourchosenpath.

AddthebinsubdirectoryofyourGoroot(forexample,c:\Go\bin)toyourPATHenvironmentvariable.SettingenvironmentvariablesunderWindows

UnderWindows,youmaysetenvironmentvariablesthroughthe"EnvironmentVariables"buttononthe"Advanced"tabofthe"System"controlpanel.SomeversionsofWindowsprovidethiscontrolpanelthroughthe"AdvancedSystemSettings"optioninsidethe"System"controlpanel.Testyourinstallation

CheckthatGoisinstalledcorrectlybysettingupaworkspaceandbuildingasimpleprogram,asfollows.

Createadirectorytocontainyourworkspace,$HOME/workforexample,andsettheGOPATHenvironmentvariabletopointtothatlocation.

$exportGOPATH=$HOME/work

Youshouldputtheabovecommandinyourshellstartupscript($HOME/.profileforexample)or,ifyouuseWindows,followtheinstructionsabovetosettheGOPATHenvironmentvariableonyoursystem.

Next,makethedirectoriessrc/github.com/user/helloinsideyourworkspace(ifyouuseGitHub,substituteyourusernameforuser),andinsidethehellodirectorycreateafilenamedhello.gowiththefollowingcontents:

packagemain

import"fmt"

funcmain(){

fmt.Printf("hello,world\n")

}

Thencompileitwiththegotool:

$goinstallgithub.com/user/hello

Theabovecommandwillputanexecutablecommandnamedhello(orhello.exe)insidethebindirectoryofyourworkspace.Executethecommandtoseethegreeting:

$$GOPATH/bin/hello

InstallationandTools

9

Page 10: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

hello,world

Ifyouseethe"hello,world"messagethenyourGoinstallationisworking.

BeforerushingofftowriteGocodepleasereadtheHowtoWriteGoCodedocument,whichdescribessomeessentialconceptsaboutusingtheGotools.UninstallingGo

ToremoveanexistingGoinstallationfromyoursystemdeletethegodirectory.Thisisusually/usr/local/gounderLinux,MacOSX,andFreeBSDorc:\GounderWindows.

YoushouldalsoremovetheGobindirectoryfromyourPATHenvironmentvariable.UnderLinuxandFreeBSDyoushouldedit/etc/profileor$HOME/.profile.IfyouinstalledGowiththeMacOSXpackagethenyoushouldremovethe/etc/paths.d/gofile.WindowsusersshouldreadthesectionaboutsettingenvironmentvariablesunderWindows.Gettinghelp

Forreal-timehelp,askthehelpfulgophersin#go-nutsontheFreenodeIRCserver.

TheofficialmailinglistfordiscussionoftheGolanguageisGoNuts.

ReportbugsusingtheGoissuetracker.

InstallationandTools

10

Page 11: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ToolsForhtml:Brackets,atexteditorforthewebbyAdobe.

ForGo:AnyIDEofyourchoicewhichhasaGolanguageplugin.

gofmt

Usage:

gofmt<filename>:printstheformattedsourcecodeontheconsole

gofmt-w<filename/foldername>:writestheformattedcodeinsidethefile(s).

gofmtformatsthesourcecodeofaGosourcefile/filesinafolder.ThebasicpointbehindtheGolanguageisthattheyhavestandardizedformatting.Thelanguageauthorswantedtocreatealanguagethatgetsthingsdonequicklyanddidn'twanttheusersofthelanguagetowageintheendlessdebateontrivialissueslikethecodeformatting.MostIDEscanbeconfiguredtorungofmtonsave.Itisrecommendedtorungofmtbeforecommittingtoversioncontrol.

godoc

DocumentationinGo,isdoneviacomments,eachexportedfunction/variableissupposedtohaverespectivecommentsonwhatitdoes.Thecommandgodocisthestandarddocumentationgenerationtool.ItextractsdocumentationcommentsonalltheGoprojectspresentin$GOPATH/src.It'sagoodpracticetogiveproperdocumentationwhileprogramming,tomakethecodeeasiertounderstandfornewcomers,forclosedsourceandopensourceprojectsalike.

Note:

godoc,bydefaultrunsontheentire$GOPATH,sodependingontheprojectsyouhaveinyour$GOPATH,itmighttakefromfewsecondstofewminutesforgodoctostarttheserver,godocdoesn'tnotifyyouwhentheserverhasstarted,theydohaveaverboseflagwhichprintswhentheserverhasstarted.Itis-v

Therearetwomodesforgodoc,

Webinterface:Usage:godoc-http=:6060-v

Forseeingdocumentationofnet/httpthelinkislocalhost:6060/pkg/net/http

Tools

11

Page 12: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

CommandlineinterfaceUsage:godocnet/http

Thiswillprovidethedocumentationofnet/http

gotest

ThisisthetestingtoolchainforGo.Foreachfile.go,thecorrespondingtestcasesshouldbepresentinafilenamedasfile_test.go.Ifmain.goisourGosourcefile,weshouldmakemain_test.gofileinthesamefolderasmain.go.TheGocompilerignoresallthe_test.gofiles.

gobuild

Weusethiscommandtodotobuildourapplication.Itparsesallthe.gofilesexceptthe_test.gofilesintheentirefolderandallsubfoldersalongwithimportedlibrariesifany,andcreatesastaticallylinkedbinary.Thebinarynameisthesameastheprojectfoldername,ifwewantacustomnameweshouldusethe-oflag.

Example:gobuild-otasks

NoteCrosscompilation

WithGo,youcancrosscompileyourapplication.BelowisthecodetocompiletheapplicationforWindowsandMacfromLinux.

envGOOS=darwinGOARCH=386gobuild-otasks.app

envGOOS=windowsGOARCH=386gobuild-otasks.exe

Iftherearenoquirksonthelibraries,shouldgiveyouabinaryfortherespectiveplatforms.

goinstall

Thiscommandcreatesastaticallylinkedbinaryandplacesitin$GOPATH/binfolder.Italsocreatesabinaryversionofallthedependentlibrariesandputsitinthe$GOPATH/pkgfolderintherespectivedirectories.

Note

Whilebuildingyourapplication,firstusegoinstallwhich'llcacheyourdependentlibraries.Thenforsubsequentchangesusegobuild,thiswillsavealotofbuildtime.Thisisbecausegobuilddoesn'tcacheanyresults,itbuildseverything.

gorun

Tools

12

Page 13: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Whilerunningyourappthroughthecommandlineyoutypicallhavetodothefollowing:gobuild-oapp./app

goruncombinesthemintoonecommand,itgeneratesandrunsabinaryofyourproject.Thebinaryfile,howeverisn'tretainedaftertherun.

goget

ThisisusedtoinstallpackagesinGo.Itinternallyclonestheversioncontrolrepositoryparameterpassedtoit,canbeanylocal/remotegitrepository.Itthenrunsgoinstallonthelibrary,makingthelibraryavailablein$GOPATH/pkg.

Tools

13

Page 14: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

WhatmakesGodifferentfromotherlanguages?TheGoprogramminglanguagewascreatedforwritinglargescalesoftwareeffectively.Thisisthereasonthelanguagehasstrictusageguidelines.InClikelanguagestherearetwofactionsofprogrammers,

thosewhodothis

publicstaticvoidmain(){

}

andthosewhodothis

publicstaticvoidmain()

{

}

ThesamecanbesaidofPythonfourspaces/tabs.

Thismightseemtobeashallowproblematthetop,butwhenthecodebaseandteamsizegrows,thenitisdifficulttomaintainthecode's"beauty"becauseofdifferentuserpreferences.Anyonecanwritecodethesedays,eitherbythemselvesorbycopyingovertheInternet,weshouldstrivetowriteelegantcode,withasmanycommentsaspossible.PythonhasPEP8,whichwascreatedtobringinsomedisciplineforformattingandnamingconventions.

GowasbuiltatGoogle,ascompanyweknowasasynonymforSearchandDistributedComputing,withtheirBorg.Theywantedalanguagethatwasfast,workedwellwithautomatedcodereviewandformattingandallowedalargeteamtowritelargescalesoftwareeffectively.Theydidn'twantusersofGotogetinvolvedintheneverendingtrivialwarsof4spacesvs1tab,hencetherearemanyrestrictionsonthelanguage.Alsoallthemajorlanguagearedecadesold,theywerecreatedinatimewherememorywascostly,thusconcurrencywasn'taproblemfortheircreators.SinceIntelIsraelcameupwiththemulticoreidea,allprocessorchipsaremulticores,Gowasdesignedwithconcurrencyinmind.AsRobPike,inhisamazingtalksaid,Concurrencyisn'tparallelism.

1. Unusedimports/variablesarecompilererrors2. Noneedtoputsemicolon'sbecausethecompileritselfwilladdsemicolonsattheend

Gobasicknowledge

14

Page 15: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ofline,thisisthereasonyoucan'twritefunctionslikethesecondway,wementionedintheabovesection

3. AllyourGocodeispresentinasinglefolder,$GOPATH,itiscalled.Saygoodbyetoyourcodethrownallaroundinyourmachine

4. gofmtwillformatyourcode,sothereisonestandardwaytowriteGocode.5. Builtinhttp/testingsupport6. Compiledlanguage,thusveryfast.7. Canwritewebappswithoutanyframeworks.

2.1Hello,GoLet'sstartwithasimpleexample,thecustomaryHelloWorld.

Program

packagemain

import"fmt"

funcmain(){

fmt.Printf("Hello,worldor你好,世界orκαλημρακóσμorこんにちは世界\n")

}

Itprintsfollowinginformation.

Hello,worldor你好,世界orκαλημρακóσμorこんにちは世界

ExplanationGoprogramsusepackages,whicharesameaslibrariesinotherlanguages.MainisaspecialpackageinGo,whenthecompilerstartscompilingthesourcecode,itstartswiththemainpackage.

package<pkgName>(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackage,andthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsare.a.

Gobasicknowledge

15

Page 16: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Perexecutableprogram,therecanbeonlyonemainpackage,andonemainfunctionwithnoargumentspassedorreturned.ThePrintffunction,isimportedfromtheformatpackagecalledfmt,weimportapackageusingimport"fmt".Whencallingafunctionnameorreferringtoavariableinsideanotherpackage,weusepkgName.FunctionNamelikefmt.Println().

Also,Gosupportsmultiplereturnvalues!

Intheexample,weprintednonASCIIcharacters.GosupportsUTF-8bydefault.

Themainpackage

EveryGoprogramshouldbeinapackage,itcanbeeitherMainoranyotherpackage.Eachpackageotherthanmainshouldbepresentasadistinctfolderinto$GOPATH.Thismeansthatyoucandirectlycreateamain.gofilewithpackagemainatit'sstartwithoutcreatingamainfolderandamain.gofileinsideit.

Careneedstobetakenwhilebuilding/runningtheapplication.

Withmainfolder:

[Tasks]$gobuildmain/main.go

[Tasks]$./main/main

Thiswillfunctioncorrectly,becauseweareintheTasksdirectorywhileexecutingourbinary,allthetemplatesandotherfilesarepresentinthisfolder.

Withoutthemainfolder

[Tasks/main]$gobuildmain.go

[Tasks/main]$./main

Here,weareintheTasks/maindirectory,thebinarywillexpectalltheotherfilesintheTasks/maindirectorywhentheyareintheTasksdirectory,

Gobasicknowledge

16

Page 17: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

2.2Gofoundation

DefinevariablesWeusethekeywordvartodefineavariable.NotethatinGothevariabletypecomesafterthevariablename.

//defineavariablewithname“variableName”andtype"type"

varvariableNametype

//definethreevariableswhichtypesare"type"

varvname1,vname2,vname3type

//defineavariablewithname“variableName”,type"type"andvalue"value"

varvariableNametype=value

/*

Definethreevariableswithtype"type",andinitializetheirvalues.

vname1isv1,vname2isv2,vname3isv3

*/

varvname1,vname2,vname3type=v1,v2,v3

Thereisashortcutmethodtodeclarevariables:

/*

Definethreevariableswithouttype"type"andwithoutkeyword"var",andinitializet

heirvalues.

vname1isv1,vname2isv2,vname3isv3

*/

vname1,vname2,vname3:=v1,v2,v3

:=canonlybeusedinsidefunctions,fordefiningglobalvariableswehavetosticktousingvar.

_variableiscalledtheblankvariableanditisusedtoignoreavalue.Thisisauselessexample,butwe'llseeitsexamplesoonenough.

_,b:=34,35//usetheblankoperatortothrowawayavalue

Unusedvariablescausecompilationerrors.Compilethefollowingcodeandseewhathappens.

Gofoundation

17

Page 18: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

funcmain(){

variint

}

ConstantsConstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntime.InGo,youcanusenumber,booleanorstringastypesofconstants.

Defineconstantsasfollows.

constconstantName=value

//youcanassigntypeofconstantsifit'snecessary

constPifloat32=3.1415926

Moreexamples.

constPi=3.1415926

consti=10000

constMaxThread=10

constprefix="astaxie_"

Elementarytypes

Boolean

Weusebooltodefineavariableasbooleantype,thevaluecanonlybetrueorfalse,andfalsewillbethedefaultvalue.(Youcannotconvertvariables'typebetweennumberandboolean!)

//samplecode

varisActivebool//globalvariable

varenabled,disabled=true,false//omittypeofvariables

functest(){

varavailablebool//localvariable

valid:=false//briefstatementofvariable

available=true//assignvaluetovariable

}

Gofoundation

18

Page 19: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Numericaltypes

Integertypesincludebothsignedandunsignedintegertypes.Gohasintanduintatthesametime,theyhavesamelength,butspecificlengthdependsonyouroperatingsystem.Theyuse32-bitin32-bitoperatingsystems,and64-bitin64-bitoperatingsystems.Goalsohastypesthathavespecificlengthincludingrune,int8,int16,int32,int64,byte,uint8,uint16,uint32,uint64.Notethatruneisaliasofint32andbyteisaliasofuint8.

Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypes,thisoperationwillcausecompileerrors.

varaint8

varbint32

c:=a+b

Althoughint32hasalongerlengththanint8,andhasthesametypeasint,youcannotassignvaluesbetweenthem.(cwillbeassertedastypeinthere)

Floattypeshavethefloat32andfloat64typesandnotypecalledfloat.Thelatteroneisthedefaulttypeifusingbriefstatement.

Gosupportscomplexnumbersaswell.complex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttype,ifyouneedasmallertype,thereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart).ItsformisRE+IMi,whereREisrealpartandIMisimaginarypart,thelastiistheimaginarynumber.Thereisaexampleofcomplexnumber.

varccomplex64=5+5i

//output:(5+5i)

fmt.Printf("Valueis:%v",c)

String

WejusttalkedabouthowGousestheUTF-8characterset.Stringsarerepresentedbydoublequotes""orbackticks `.

Gofoundation

19

Page 20: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//samplecode

varfrenchHellostring//basicformtodefinestring

varemptyStringstring=""//defineastringwithemptystring

functest(){

no,yes,maybe:="no","yes","maybe"//briefstatement

japaneseHello:="Ohaiou"

frenchHello="Bonjour"//basicformofassignvalues

}

It'simpossibletochangestringvaluesbyindex.Youwillgeterrorswhenyoucompilethefollowingcode.

varsstring="hello"

s[0]='c'

WhatifIreallywanttochangejustonecharacterinastring?Trythefollowingcode.

s:="hello"

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

c[0]='c'

s2:=string(c)//convertbacktostringtype

fmt.Printf("%s\n",s2)

Youusethe+operatortocombinetwostrings.

s:="hello,"

m:="world"

a:=s+m

fmt.Printf("%s\n",a)

andalso.

s:="hello"

s="c"+s[1:]//youcannotchangestringvaluesbyindex,butyoucangetvaluesin

stead.

fmt.Printf("%s\n",s)

WhatifIwanttohaveamultiple-linestring?

m:=`hello

world`

willnotescapeanycharactersinastring.

Gofoundation

20

Page 21: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Errortypes

Gohasoneerrortypeforpurposeofdealingwitherrormessages.Thereisalsoapackagecallederrorstohandleerrors.

err:=errors.New("emitmachodwarf:elfheadercorrupted")

iferr!=nil{

fmt.Print(err)

}

Underlyingdatastructure

ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCox'sBlog.Asyoucansee,Goutilizesblocksofmemorytostoredata.

Figure2.1Gounderlyingdatastructure

Someskills

Definebygroup

Ifyouwanttodefinemultipleconstants,variablesorimportpackages,youcanusethegroupform.

Basicform.

import"fmt"

import"os"

consti=100

constpi=3.1415

constprefix="Go_"

variint

varpifloat32

varprefixstring

Groupform.

Gofoundation

21

Page 22: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

import(

"fmt"

"os"

)

const(

i=100

pi=3.1415

prefix="Go_"

)

var(

iint

pifloat32

prefixstring

)

Unlessyouassignthevalueofconstantisiota,thefirstvalueofconstantinthegroupconst()willbe0.Iffollowingconstantsdon'tassignvaluesexplicitly,theirvalueswillbethesameasthelastone.Ifthevalueoflastconstantisiota,thevaluesoffollowingconstantswhicharenotassignedareiotaalso.

iotaenumerate

Gohasonekeywordcallediota,thiskeywordistomakeenum,itbeginswith0,increasedby1.

const(

x=iota//x==0

y=iota//y==1

z=iota//z==2

w//Ifthereisnoexpressionaftertheconstantsname,itusesthelastexpress

ion,

//soit'ssayingw=iotaimplicitly.Thereforew==3,andyandzbothcanomit

"=iota"aswell.

)

constv=iota//onceiotameetskeyword`const`,itresetsto`0`,sov=0.

const(

e,f,g=iota,iota,iota//e=0,f=0,g=0valuesofiotaaresameinoneline.

)

Somerules

ThereasonthatGoisconcisebecauseithassomedefaultbehaviors.

Gofoundation

22

Page 23: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Anyvariablethatbeginswithacapitallettermeansitwillbeexported,privateotherwise.Thesameruleappliesforfunctionsandconstants,nopublicorprivatekeywordexistsinGo.

array,slice,map

array

arrayisanarrayobviously,wedefineoneasfollows.

vararr[n]type

in[n]type,nisthelengthofthearray,typeisthetypeofitselements.Likeotherlanguages,weuse[]togetorsetelementvalueswithinarrays.

vararr[10]int//anarrayoftype[10]int

arr[0]=42//arrayis0-based

arr[1]=13//assignvaluetoelement

fmt.Printf("Thefirstelementis%d\n",arr[0])

//getelementvalue,itreturns42

fmt.Printf("Thelastelementis%d\n",arr[9])

//itreturnsdefaultvalueof10thelementinthisarray,whichis0inthiscase.

Becauselengthisapartofthearraytype,[3]intand[4]intaredifferenttypes,sowecannotchangethelengthofarrays.Whenyouusearraysasarguments,functionsgettheircopiesinsteadofreferences!Ifyouwanttousereferences,youmaywanttouseslice.We'lltalkaboutlater.

It'spossibletouse:=whenyoudefinearrays.

a:=[3]int{1,2,3}//defineanintarraywith3elements

b:=[10]int{1,2,3}

//defineaintarraywith10elements,ofwhichthefirstthreeareassigned.

//Therestofthemusethedefaultvalue0.

c:=[...]int{4,5,6}//use`…`toreplacethelengthparameterandGowillcalculat

eitforyou.

Youmaywanttousearraysasarrays'elements.Let'sseehowtodothis.

Gofoundation

23

Page 24: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//defineatwo-dimensionalarraywith2elements,andeachelementhas4elements.

doubleArray:=[2][4]int{[4]int{1,2,3,4},[4]int{5,6,7,8}}

//Thedeclarationcanbewrittenmoreconciselyasfollows.

easyArray:=[2][4]int{{1,2,3,4},{5,6,7,8}}

Arrayunderlyingdatastructure.

Figure2.2Multidimensionalarraymappingrelationship

slice

Inmanysituations,thearraytypeisnotagoodchoice-forinstancewhenwedon'tknowhowlongthearraywillbewhenwedefineit.Thus,weneeda"dynamicarray".ThisiscalledsliceinGo.

sliceisnotreallyadynamicarray.It'sareferencetype.slicepointstoanunderlyingarraywhosedeclarationissimilartoarray,butdoesn'tneedlength.

//justlikedefininganarray,butthistime,weexcludethelength.

varfslice[]int

Thenwedefineaslice,andinitializeitsdata.

slice:=[]byte{'a','b','c','d'}

slicecanredefineexistingslicesorarrays.sliceusesarray[i:j]toslice,whereiisthestartindexandjisendindex,butnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i.

//defineanarraywith10elementswhosetypesarebytes

varar=[10]byte{'a','b','c','d','e','f','g','h','i','j'}

//definetwosliceswithtype[]byte

vara,b[]byte

//'a'pointstoelementsfrom3rdto5thinarrayar.

a=ar[2:5]

//now'a'haselementsar[2],ar[3]andar[4]

//'b'isanothersliceofarrayar

b=ar[3:5]

//now'b'haselementsar[3]andar[4]

Gofoundation

24

Page 25: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Noticethedifferencesbetweensliceandarraywhenyoudefinethem.Weuse[…]toletGocalculatelengthbutuse[]todefinesliceonly.

Theirunderlyingdatastructure.

Figure2.3Correspondencebetweensliceandarray

slicehassomeconvenientoperations.

sliceis0-based,ar[:n]equalstoar[0:n]Thesecondindexwillbethelengthofsliceifomitted,ar[n:]equalstoar[n:len(ar)].Youcanusear[:]toslicewholearray,reasonsareexplainedinfirsttwostatements.

Moreexamplespertainingtoslice

//defineanarray

vararray=[10]byte{'a','b','c','d','e','f','g','h','i','j'}

//definetwoslices

varaSlice,bSlice[]byte

//someconvenientoperations

aSlice=array[:3]//equalstoaSlice=array[0:3]aSlicehaselementsa,b,c

aSlice=array[5:]//equalstoaSlice=array[5:10]aSlicehaselementsf,g,h,i,j

aSlice=array[:]//equalstoaSlice=array[0:10]aSlicehasallelements

//slicefromslice

aSlice=array[3:7]//aSlicehaselementsd,e,f,g,len=4,cap=7

bSlice=aSlice[1:3]//bSlicecontainsaSlice[1],aSlice[2],soithaselementse,f

bSlice=aSlice[:3]//bSlicecontainsaSlice[0],aSlice[1],aSlice[2],soithasd,e

,f

bSlice=aSlice[0:5]//slicecouldbeexpandedinrangeofcap,nowbSlicecontainsd

,e,f,g,h

bSlice=aSlice[:]//bSlicehassameelementsasaSlicedoes,whichared,e,f,g

sliceisareferencetype,soanychangeswillaffectothervariablespointingtothesamesliceorarray.Forinstance,inthecaseofaSliceandbSliceabove,ifyouchangethevalueofanelementinaSlice,bSlicewillbechangedaswell.

sliceislikeastructbydefinitionanditcontains3parts.

Apointerthatpointstowhereslicestarts.Thelengthofslice.Capacity,thelengthfromstartindextoendindexofslice.

Gofoundation

25

Page 26: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Array_a:=[10]byte{'a','b','c','d','e','f','g','h','i','j'}

Slice_a:=Array_a[2:5]

Theunderlyingdatastructureofthecodeaboveasfollows.

Figure2.4Arrayinformationofslice

Therearesomebuilt-infunctionsforslice.

lengetsthelengthofslice.capgetsthemaximumlengthofsliceappendappendsoneormoreelementstoslice,andreturnsslice.copycopieselementsfromoneslicetotheother,andreturnsthenumberofelementsthatwerecopied.

Attention:appendwillchangethearraythatslicepointsto,andaffectotherslicesthatpointtothesamearray.Also,ifthereisnotenoughlengthfortheslice((cap-len)==0),appendreturnsanewarrayforthisslice.Whenthishappens,otherslicespointingtotheoldarraywillnotbeaffected.

map

mapbehaveslikeadictionaryinPython.Usetheformmap[keyType]valueTypetodefineit.

Let'sseesomecode.The'set'and'get'valuesinmaparesimilartoslice,howevertheindexinslicecanonlybeoftype'int'whilemapcanusemuchmorethanthat:forexampleint,string,orwhateveryouwant.Also,theyareallabletouse==and!=tocomparevalues.

//usestringasthekeytype,intasthevaluetype,and`make`initializeit.

varnumbersmap[string]int

//anotherwaytodefinemap

numbers:=make(map[string]int)

numbers["one"]=1//assignvaluebykey

numbers["ten"]=10

numbers["three"]=3

fmt.Println("Thethirdnumberis:",numbers["three"])//getvalues

//Itprints:Thethirdnumberis:3

Somenoteswhenyouusemap.

mapisdisorderly.Everytimeyouprintmapyouwillgetdifferentresults.It'simpossible

Gofoundation

26

Page 27: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

togetvaluesbyindex-youhavetousekey.mapdoesn'thaveafixedlength.It'sareferencetypejustlikeslice.lenworksformapalso.Itreturnshowmanykeysthatmaphas.It'squiteeasytochangethevaluethroughmap.Simplyusenumbers["one"]=11tochangethevalueofkeyoneto11.

Youcanuseformkey:valtoinitializemap'svalues,andmaphasbuilt-inmethodstocheckifthekeyexists.

Usedeletetodeleteanelementinmap.

//Initializeamap

rating:=map[string]float32{"C":5,"Go":4.5,"Python":4.5,"C++":2}

//maphastworeturnvalues.Forthesecondreturnvalue,ifthekeydoesn't

//exist,'ok'returnsfalse.Itreturnstrueotherwise.

csharpRating,ok:=rating["C#"]

ifok{

fmt.Println("C#isinthemapanditsratingis",csharpRating)

}else{

fmt.Println("WehavenoratingassociatedwithC#inthemap")

}

delete(rating,"C")//deleteelementwithkey"c"

AsIsaidabove,mapisareferencetype.Iftwomapspointtosameunderlyingdata,anychangewillaffectbothofthem.

m:=make(map[string]string)

m["Hello"]="Bonjour"

m1:=m

m1["Hello"]="Salut"//nowthevalueofm["hello"]isSalut

make,new

makedoesmemoryallocationforbuilt-inmodels,suchasmap,slice,andchannel,whilenewisfortypes'memoryallocation.

new(T)allocateszero-valuetotypeT'smemory,returnsitsmemoryaddress,whichisthevalueoftype*T.ByGo'sdefinition,itreturnsapointerwhichpointstotypeT'szero-value.

newreturnspointers.

Thebuilt-infunctionmake(T,args)hasdifferentpurposesthannew(T).makecanbeusedforslice,map,andchannel,andreturnsatypeTwithaninitialvalue.Thereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbefore

Gofoundation

27

Page 28: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

theypointtothem.Forexample,aslicecontainsapointerthatpointstotheunderlyingarray,lengthandcapacity.Beforethesedataareinitialized,sliceisnil,soforslice,mapandchannel,makeinitializestheirunderlyingdataandassignssomesuitablevalues.

makereturnsnon-zerovalues.

Thefollowingpictureshowshownewandmakearedifferent.

Figure2.5Underlyingmemoryallocationofmakeandnew

Zero-valuedoesnotmeanemptyvalue.It'sthevaluethatvariablesdefaulttoinmostcases.Hereisalistofsomezero-values.

int0

int80

int320

int640

uint0x0

rune0//theactualtypeofruneisint32

byte0x0//theactualtypeofbyteisuint8

float320//lengthis4byte

float640//lengthis8byte

boolfalse

string""

Gofoundation

28

Page 29: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

2.3Controlstatementsandfunctions

Controlstatement

if

ifdoesn'tneedparenthesesinGo.

ifx>10{

//whenxisgreaterthan10

//programentersthisblock

fmt.Println("xisgreaterthan10")

}else{

//whenxissmallerthan10

//programentersthisblock

fmt.Println("xislessthanorequalto10")

}

Goallowsustoinitializeandusevariablesiniflikethis:

//initializex,thencheckifxgreaterthan

ifx:=computedValue();x>10{

fmt.Println("xisgreaterthan10")

}else{

fmt.Println("xislessthan10")

}

//thefollowingcodewillnotcompile

fmt.Println(x)

Formultipleconditionsweusetheelseifblock

ifinteger==3{

fmt.Println("Theintegerisequalto3")

}elseifinteger<3{

fmt.Println("Theintegerislessthan3")

}else{

fmt.Println("Theintegerisgreaterthan3")

}

goto

Controlstatementsandfunctions

29

Page 30: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Gohasagotokeyword,butbecarefulwhenyouuseit.gotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock.

funcmyFunc(){

i:=0

Here://labelendswith":"

fmt.Println(i)

i++

gotoHere//jumptolabel"Here"

}

Thelabelnameiscasesensitive.

for

Godoesnothavewhile,dowhile.Justafor,whichisthemostpowerfulcontrollogic.Itcanreaddatainloopsanditerativeoperations,justlikewhile.Likeif,fordoesn'tneedparenthesis.

forexpression1;expression2;expression3{

//...

}

packagemain

import"fmt"

funcmain(){

sum:=0;

forindex:=0;index<10;index++{

sum+=index

}

fmt.Println("sumisequalto",sum)

}

//Print:sumisequalto45

Wecanomitoneormoreexpressions.

sum:=1

for;sum<1000;{

sum+=sum

}

for{

//thisisaninfiniteloop

}

Controlstatementsandfunctions

30

Page 31: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Usingforlikeawhile

sum:=1

forsum<1000{

sum+=sum

}

breakandcontinue

1. break:jumpsoutoftheloop.Ifyouhavenestedloops,usebreakalongwithlabels.2. continueskipsthecurrentloopandstartsthenextone

forindex:=10;index>0;index--{

ifindex==5{

break//orcontinue

}

fmt.Println(index)

}//breakprints10、9、8、7、6//continueprints10、9、8、7、6、4、3、2、1

forcanreaddatafromsliceandmapwhenitisusedtogetherwithrange.

fork,v:=rangemap{

fmt.Println("map'skey:",k)

fmt.Println("map'sval:",v)

}

BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudon'tusevaluesthatweredefined,youmaywanttouse_todiscardcertainreturnvalues.

for_,v:=rangemap{

fmt.Println("map'sval:",v)

}

switch

Sometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogic,whichmaymakeitdifficulttoreadandmaintaininthefuture.Theswitchstatementsolvesthisproblem.

Controlstatementsandfunctions

31

Page 32: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

switchsExpr{

caseexpr1:

someinstructions

caseexpr2:

someotherinstructions

caseexpr3:

someotherinstructions

default:

othercode

}

ThetypeofsExpr,expr1,expr2,andexpr3mustbethesame.switchisveryflexible.Conditionsdon'thavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditions.Ifthereisnostatementafterthekeywordswitch,thenitmatchestrue.

i:=10

switchi{

case1:

fmt.Println("iisequalto1")

case2,3,4:

fmt.Println("iisequalto2,3or4")

case10:

fmt.Println("iisequalto10")

default:

fmt.Println("AllIknowisthatiisaninteger")

}

Inthefifthline,weputmanyvaluesinonecase,andwedon'tneedtoaddthebreakkeywordattheendofcase'sbody.Itwilljumpoutoftheswitchbodyonceitmatchedanycase.Ifyouwanttocontinuetomatchingmorecases,youneedtousethefallthroughstatement.

Controlstatementsandfunctions

32

Page 33: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

integer:=6

switchinteger{

case4:

fmt.Println("integer<=4")

fallthrough

case5:

fmt.Println("integer<=5")

fallthrough

case6:

fmt.Println("integer<=6")

fallthrough

case7:

fmt.Println("integer<=7")

fallthrough

case8:

fmt.Println("integer<=8")

fallthrough

default:

fmt.Println("defaultcase")

}

Thisprogramprintsthefollowinginformation.

integer<=6

integer<=7

integer<=8

defaultcase

FunctionsUsethefunckeywordtodefineafunction.

funcfuncName(input1type1,input2type2)(output1type1,output2type2){

//functionbody

//multi-valuereturn

returnvalue1,value2

}

Wecanextrapolatethefollowinginformationfromtheexampleabove.

UsekeywordfunctodefineafunctionfuncName.Functionshavezero,oneormorethanonearguments.Theargumenttypecomesaftertheargumentnameandargumentsareseparatedby,.Functionscanreturnmultiplevalues.Therearetworeturnvaluesnamedoutput1andoutput2,youcanomittheirnames

Controlstatementsandfunctions

33

Page 34: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

andusetheirtypeonly.Ifthereisonlyonereturnvalueandyouomittedthename,youdon'tneedbracketsforthereturnvalues.Ifthefunctiondoesn'thavereturnvalues,youcanomitthereturnparametersaltogether.Ifthefunctionhasreturnvalues,youhavetousethereturnstatementsomewhereinthebodyofthefunction.

Let'sseeonepracticalexample.(calculatemaximumvalue)

packagemain

import"fmt"

//returngreatervaluebetweenaandb

funcmax(a,bint)int{

ifa>b{

returna

}

returnb

}

funcmain(){

x:=3

y:=4

z:=5

max_xy:=max(x,y)//callfunctionmax(x,y)

max_xz:=max(x,z)//callfunctionmax(x,z)

fmt.Printf("max(%d,%d)=%d\n",x,y,max_xy)

fmt.Printf("max(%d,%d)=%d\n",x,z,max_xz)

fmt.Printf("max(%d,%d)=%d\n",y,z,max(y,z))//callfunctionhere

}

Intheaboveexample,therearetwoargumentsinthefunctionmax,theirtypesarebothintsothefirsttypecanbeomitted.Forinstance,a,bintinsteadofaint,bint.Thesamerulesapplyforadditionalarguments.Noticeherethatmaxonlyhasonereturnvalue,soweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit.

Multi-valuereturn

Controlstatementsandfunctions

34

Page 35: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import"fmt"

//returnresultsofA+BandA*B

funcSumAndProduct(A,Bint)(int,int){

returnA+B,A*B

}

funcmain(){

x:=3

y:=4

xPLUSy,xTIMESy:=SumAndProduct(x,y)

fmt.Printf("%d+%d=%d\n",x,y,xPLUSy)

fmt.Printf("%d*%d=%d\n",x,y,xTIMESy)

}

Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalso.Ifwenamedthereturnvalues,wewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomatically.Noticethatifyourfunctionsaregoingtobeusedoutsideofthepackage,whichmeansyourfunctionnamesstartwithacapitalletter,you'dbetterwritecompletestatementsforreturn;itmakesyourcodemorereadable.

funcSumAndProduct(A,Bint)(addint,multipliedint){

add=A+B

multiplied=A*B

return

}

Variadicfunctions

Gosupportsfunctionswithavariablenumberofarguments.Thesefunctionsarecalled"variadic",whichmeansthefunctionallowsanuncertainnumbersofarguments.

funcmyfunc(arg...int){}

arg…inttellsGothatthisisafunctionthathasvariablearguments.Noticethattheseargumentsaretypeint.Inthebodyoffunction,theargbecomesasliceofint.

for_,n:=rangearg{

fmt.Printf("Andthenumberis:%d\n",n)

}

Controlstatementsandfunctions

35

Page 36: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Passbyvalueandpointers

Whenwepassanargumenttothefunctionthatwascalled,thatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable.

Let'sseeoneexampleinordertoprovewhati'msaying.

packagemain

import"fmt"

//simplefunctiontoadd1toa

funcadd1(aint)int{

a=a+1//wechangevalueofa

returna//returnnewvalueofa

}

funcmain(){

x:=3

fmt.Println("x=",x)//shouldprint"x=3"

x1:=add1(x)//calladd1(x)

fmt.Println("x+1=",x1)//shouldprint"x+1=4"

fmt.Println("x=",x)//shouldprint"x=3"

}

Eventhoughwecalledadd1withx,theoriginvalueofxdoesn'tchange.

Thereasonisverysimple:whenwecalledadd1,wegaveacopyofxtoit,notthexitself.

NowyoumayaskhowIcanpasstherealxtothefunction.

Weneedusepointershere.Weknowvariablesarestoredinmemoryandtheyhavesomememoryaddresses.So,ifwewanttochangethevalueofavariable,wemustchangeitsmemoryaddress.Thereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalue.Herewepass&xtothefunction,andchangetheargument'stypetothepointertype*int.Beawarethatwepassacopyofthepointer,notcopyofvalue.

Controlstatementsandfunctions

36

Page 37: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import"fmt"

//simplefunctiontoadd1toa

funcadd1(a*int)int{

*a=*a+1//wechangedvalueofa

return*a//returnnewvalueofa

}

funcmain(){

x:=3

fmt.Println("x=",x)//shouldprint"x=3"

x1:=add1(&x)//calladd1(&x)passmemoryaddressofx

fmt.Println("x+1=",x1)//shouldprint"x+1=4"

fmt.Println("x=",x)//shouldprint"x=4"

}

Nowwecanchangethevalueofxinthefunctions.Whydoweusepointers?Whataretheadvantages?

Allowsustousemorefunctionstooperateononevariable.Lowcostbypassingmemoryaddresses(8bytes),copyisnotanefficientway,bothintermsoftimeandspace,topassvariables.string,sliceandmaparereferencetypes,sotheyusepointerswhenpassingtofunctionsbydefault.(Attention:Ifyouneedtochangethelengthofslice,youhavetopasspointersexplicitly)

defer

Gohasawelldesignedkeywordcalleddefer.Youcanhavemanydeferstatementsinonefunction;theywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctions.Inthecasewheretheprogramopenssomeresourcefiles,thesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrors.Let'sseesomeexamples.

Controlstatementsandfunctions

37

Page 38: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

funcReadWrite()bool{

file.Open("file")

//Dosomework

iffailureX{

file.Close()

returnfalse

}

iffailureY{

file.Close()

returnfalse

}

file.Close()

returntrue

}

Wesawsomecodebeingrepeatedseveraltimes.defersolvesthisproblemverywell.Itdoesn'tonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable.

funcReadWrite()bool{

file.Open("file")

deferfile.Close()

iffailureX{

returnfalse

}

iffailureY{

returnfalse

}

returntrue

}

Iftherearemorethanonedefers,theywillexecutebyreverseorder.Thefollowingexamplewillprint43210.

fori:=0;i<5;i++{

deferfmt.Printf("%d",i)

}

Functionsasvaluesandtypes

FunctionsarealsovariablesinGo,wecanusetypetodefinethem.Functionsthathavethesamesignaturecanbeseenasthesametype.

Controlstatementsandfunctions

38

Page 39: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

typetypeNamefunc(input1inputType1,input2inputType2[,...])(result1resultType1

[,...])

What'stheadvantageofthisfeature?Theansweristhatitallowsustopassfunctionsasvalues.

packagemain

import"fmt"

typetestIntfunc(int)bool//defineafunctiontypeofvariable

funcisOdd(integerint)bool{

ifinteger%2==0{

returnfalse

}

returntrue

}

funcisEven(integerint)bool{

ifinteger%2==0{

returntrue

}

returnfalse

}

//passthefunction`f`asanargumenttoanotherfunction

funcfilter(slice[]int,ftestInt)[]int{

varresult[]int

for_,value:=rangeslice{

iff(value){

result=append(result,value)

}

}

returnresult

}

funcmain(){

slice:=[]int{1,2,3,4,5,7}

fmt.Println("slice=",slice)

odd:=filter(slice,isOdd)//usefunctionasvalues

fmt.Println("Oddelementsofsliceare:",odd)

even:=filter(slice,isEven)

fmt.Println("Evenelementsofsliceare:",even)

}

It'sveryusefulwhenweuseinterfaces.AsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestInt.Therefore,wecanhavecomplexlogicinourprograms,whilemaintaining

Controlstatementsandfunctions

39

Page 40: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

flexibilityinourcode.

PanicandRecover

Godoesn'thavetry-catchstructurelikeJavadoes.Insteadofthrowingexceptions,Gousespanicandrecovertodealwitherrors.However,youshouldn'tusepanicverymuch,althoughit'spowerful.

Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatus.WhenafunctionFcallspanic,Fwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecute.ThenFgoesbacktothebreakpointwhichcausedthepanicstatus.Theprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutine.paniccanbeproducedbycallingpanicintheprogram,andsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors.

Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatus.Callingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatus.Itcatchespanicvaluesiftheprogramisinthepanicstatus,anditgetsniliftheprogramisnotinpanicstatus.

Thefollowingexampleshowshowtousepanic.

varuser=os.Getenv("USER")

funcinit(){

ifuser==""{

panic("novaluefor$USER")

}

}

Thefollowingexampleshowshowtocheckpanic.

functhrowsPanic(ffunc())(bbool){

deferfunc(){

ifx:=recover();x!=nil{

b=true

}

}()

f()//iffcausespanic,itwillrecover

return

}

mainfunctionandinitfunction

Controlstatementsandfunctions

40

Page 41: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Gohastworetentionswhicharecalledmainandinit,whereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackage.Thesetwofunctionsarenotabletohaveargumentsorreturnvalues.Eventhoughwecanwritemanyinitfunctionsinonepackage,Istronglyrecommendwritingonlyoneinitfunctionforeachpackage.

Goprogramswillcallinit()andmain()automatically,soyoudon'tneedtocallthembyyourself.Foreverypackage,theinitfunctionisoptional,butpackagemainhasoneandonlyonemainfunction.

Programsinitializeandbeginexecutionfromthemainpackage.Ifthemainpackageimportsotherpackages,theywillbeimportedinthecompiletime.Ifonepackageisimportedmanytimes,itwillbeonlycompiledonce.Afterimportingpackages,programswillinitializetheconstantsandvariableswithintheimportedpackages,thenexecutetheinitfunctionifitexists,andsoon.Afteralltheotherpackagesareinitialized,programswillinitializeconstantsandvariablesinthemainpackage,thenexecutetheinitfunctioninsidethepackageifitexists.Thefollowingfigureshowstheprocess.

Figure2.6FlowofprogramsinitializationinGo

import

WeuseimportveryofteninGoprogramsasfollows.

import(

"fmt"

)

Thenweusefunctionsinthatpackageasfollows.

fmt.Println("helloworld")

fmtisfromGostandardlibrary,itislocatedwithin$GOROOT/pkg.Gosupportsthird-partypackagesintwoways.

1. Relativepathimport"./model"//loadpackageinthesamedirectory,Idon'trecommendthisway.

2. Absolutepathimport"shorturl/model"//loadpackageinpath"$GOPATH/pkg/shorturl/model"

Therearesomespecialoperatorswhenweimportpackages,andbeginnersarealwaysconfusedbytheseoperators.

Controlstatementsandfunctions

41

Page 42: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

1. Dotoperator.Sometimeweseepeopleusefollowingwaytoimportpackages.

import(

."fmt"

)

Thedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackage.Nowfmt.Printf("Helloworld")becomestoPrintf("Helloworld").

2. Aliasoperation.Itchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage.

import(

f"fmt"

)

Nowfmt.Printf("Helloworld")becomestof.Printf("Helloworld").

3. _operator.Thisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou.

import(

"database/sql"

_"github.com/ziutek/mymysql/godrv"

)

The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunction,andwearenotsureifwanttousethefunctionsbelongingtothatpackage.

Controlstatementsandfunctions

42

Page 43: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

2.4struct

structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguages.Forexample,wecancreateatypecalledpersontorepresentaperson,withfieldsnameandage.Wecallthiskindoftypeastruct.

typepersonstruct{

namestring

ageint

}

Therearetwofields.

nameisastringusedtostoreaperson'sname.ageisaintusedtostoreaperson'sage.

Let'sseehowtouseit.

typepersonstruct{

namestring

ageint

}

varPperson//pispersontype

P.name="Astaxie"//assign"Astaxie"tothefield'name'ofp

P.age=25//assign25tofield'age'ofp

fmt.Printf("Theperson'snameis%s\n",P.name)//accessfield'name'ofp

Therearethreemorewaystodefineastruct.

Assigninitialvaluesbyorder

P:=person{"Tom",25}

Usetheformatfield:valuetoinitializethestructwithoutorder

P:=person{age:24,name:"Bob"}

struct

43

Page 44: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Defineananonymousstruct,theninitializeit

P:=struct{namestring;ageint}{"Amy",18}

Let'sseeacompleteexample.

packagemain

import"fmt"

//defineanewtype

typepersonstruct{

namestring

ageint

}

//comparetheageoftwopeople,thenreturnthe

//olderpersonanddifferencesofage

//structispassedbyvalue

funcOlder(p1,p2person)(person,int){

ifp1.age>p2.age{

returnp1,p1.age-p2.age

}

returnp2,p2.age-p1.age

}

funcmain(){

vartomperson

//initialization

tom.name,tom.age="Tom",18

//initializetwovaluesbyformat"field:value"

bob:=person{age:25,name:"Bob"}

//initializetwovalueswithorder

paul:=person{"Paul",43}

tb_Older,tb_diff:=Older(tom,bob)

tp_Older,tp_diff:=Older(tom,paul)

bp_Older,bp_diff:=Older(bob,paul)

fmt.Printf("Of%sand%s,%sisolderby%dyears\n",

tom.name,bob.name,tb_Older.name,tb_diff)

fmt.Printf("Of%sand%s,%sisolderby%dyears\n",

tom.name,paul.name,tp_Older.name,tp_diff)

fmt.Printf("Of%sand%s,%sisolderby%dyears\n",

bob.name,paul.name,bp_Older.name,bp_diff)

}

struct

44

Page 45: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

embeddedfieldsinstruct

I'vejustintroducedtoyouhowtodefineastructwithfieldnamesandtype.Infact,Gosupportsfieldswithoutnames,butwithtypes.Wecalltheseembeddedfields.

Whentheembeddedfieldisastruct,allthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembdedded.

Let'sseeoneexample.

packagemain

import"fmt"

typeHumanstruct{

namestring

ageint

weightint

}

typeStudentstruct{

Human//embeddedfield,itmeansStudentstruct

//includesallfieldsthatHumanhas.

specialtystring

}

funcmain(){

//initializeastudent

mark:=Student{Human{"Mark",25,120},"ComputerScience"}

//accessfields

fmt.Println("Hisnameis",mark.name)

fmt.Println("Hisageis",mark.age)

fmt.Println("Hisweightis",mark.weight)

fmt.Println("Hisspecialtyis",mark.specialty)

//modifynotes

mark.specialty="AI"

fmt.Println("Markchangedhisspecialty")

fmt.Println("Hisspecialtyis",mark.specialty)

//modifyage

fmt.Println("Markbecomeold")

mark.age=46

fmt.Println("Hisageis",mark.age)

//modifyweight

fmt.Println("Markisnotanathletanymore")

mark.weight+=60

fmt.Println("Hisweightis",mark.weight)

}

struct

45

Page 46: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Figure2.7EmbeddinginStudentandHuman

WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHuman.Thisishowembeddedfieldswork.It'sverycool,isn'tit?Holdon,there'ssomethingcooler!YoucanevenuseStudenttoaccessHumaninthisembeddedfield!

mark.Human=Human{"Marcus",55,220}

mark.Human.age-=1

AllthetypesinGocanbeusedasembeddedfields.

packagemain

import"fmt"

typeSkills[]string

typeHumanstruct{

namestring

ageint

weightint

}

typeStudentstruct{

Human//structasembeddedfield

Skills//stringsliceasembeddedfield

int//built-intypeasembeddedfield

specialtystring

}

funcmain(){

//initializeStudentJane

jane:=Student{Human:Human{"Jane",35,100},specialty:"Biology"}

//accessfields

fmt.Println("Hernameis",jane.name)

fmt.Println("Herageis",jane.age)

fmt.Println("Herweightis",jane.weight)

fmt.Println("Herspecialtyis",jane.specialty)

//modifyvalueofskillfield

jane.Skills=[]string{"anatomy"}

fmt.Println("Herskillsare",jane.Skills)

fmt.Println("Sheacquiredtwonewones")

jane.Skills=append(jane.Skills,"physics","golang")

fmt.Println("Herskillsnoware",jane.Skills)

//modifyembeddedfield

jane.int=3

fmt.Println("Herpreferrednumberis",jane.int)

}

struct

46

Page 47: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Intheaboveexample,wecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem.

Thereisonemoreproblemhowever.IfHumanhasafieldcalledphoneandStudenthasafieldwithsamename,whatshouldwedo?

Gouseaverysimplewaytosolveit.Theouterfieldsgetupperaccesslevels,whichmeanswhenyouaccessstudent.phone,wewillgetthefieldcalledphoneinstudent,nottheoneintheHumanstruct.Thisfeaturecanbesimplyseenasfieldoverloading.

packagemain

import"fmt"

typeHumanstruct{

namestring

ageint

phonestring//Humanhasphonefield

}

typeEmployeestruct{

Human//embeddedfieldHuman

specialtystring

phonestring//phoneinemployee

}

funcmain(){

Bob:=Employee{Human{"Bob",34,"777-444-XXXX"},

"Designer","333-222"}

fmt.Println("Bob'sworkphoneis:",Bob.phone)

//accessphonefieldinHuman

fmt.Println("Bob'spersonalphoneis:",Bob.Human.phone)

}

struct

47

Page 48: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Object-orientedGodoesn'tallowustohavefunctionsasapartofstructs,butitdoesallowustobindfunctionstostructs,thesefunctionsarecalledmethods.Thesemethodscanonlybecalledbyaninstanceofthestruct.

methodSupposeyoudefinea"rectangle"structandyouwanttocalculateitsarea.We'dtypicallyusethefollowingcodetoachievethisgoal.

packagemain

import"fmt"

typeRectanglestruct{

width,heightfloat64

}

funcarea(rRectangle)float64{

returnr.width*r.height

}

funcmain(){

r1:=Rectangle{12,2}

r2:=Rectangle{9,4}

fmt.Println("Areaofr1is:",area(r1))

fmt.Println("Areaofr2is:",area(r2))

}

Theaboveexamplecancalculatearectangle'sarea.Weusethefunctioncalledarea,butit'snotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages).Thefunctionandstructaretwoindependentthingsasyoumaynotice.

It'snotaproblemsofar.However,ifyoualsohavetocalculatetheareaofacircle,square,pentagon,oranyotherkindofshape,youaregoingtoneedtoaddadditionalfunctionswithverysimilarnames.

Figure2.8Relationshipbetweenfunctionandstruct

Obviouslythat'snotcool.Also,theareashouldreallybethepropertyofacircleorrectangle.

Object-oriented

48

Page 49: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Forthosereasons,wehavethemethodconcept.methodisaffiliatedwithtype.Ithasthesamesyntaxasfunctionsdoexceptforanadditionalparameterafterthefunckeywordcalledthereceiver,whichisthemainbodyofthatmethod.

Usingthesameexample,Rectangle.area()belongsdirectlytorectangle,insteadofasaperipheralfunction.Morespecifically,length,widthandarea()allbelongtorectangle.

AsRobPikesaid.

"Amethodisafunctionwithanimplicitfirstargument,calledareceiver."

Syntaxofmethod.

func(rReceiverType)funcName(parameters)(results)

Let'schangeourexampleusingmethodinstead.

Object-oriented

49

Page 50: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"fmt"

"math"

)

typeRectanglestruct{

width,heightfloat64

}

typeCirclestruct{

radiusfloat64

}

func(rRectangle)area()float64{

returnr.width*r.height

}

func(cCircle)area()float64{

returnc.radius*c.radius*math.Pi

}

funcmain(){

r1:=Rectangle{12,2}

r2:=Rectangle{9,4}

c1:=Circle{10}

c2:=Circle{25}

fmt.Println("Areaofr1is:",r1.area())

fmt.Println("Areaofr2is:",r2.area())

fmt.Println("Areaofc1is:",c1.area())

fmt.Println("Areaofc2is:",c2.area())

}

Notesforusingmethods.

Ifthenameofmethodsarethesamebuttheydon'tsharethesamereceivers,theyarenotthesame.Methodsareabletoaccessfieldswithinreceivers.Use.tocallamethodinthestruct,thesamewayfieldsarecalled.

Figure2.9Methodsaredifferentindifferentstructs

Intheexampleabove,thearea()methodsbelongtobothRectangleandCirclerespectively,sothereceiversareRectangleandCircle.

Object-oriented

50

Page 51: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Onethingthat'sworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvalue,notbyreference.Thedifferencebetweenthemisthatamethodcanchangeitsreceiver'svalueswhenthereceiverispassedbyreference,anditgetsacopyofthereceiverwhenthereceiverispassedbyvalue.

Canthereceiveronlybeastruct?Ofcoursenot.Anytypecanbethereceiverofamethod.Youmaybeconfusedaboutcustomizedtypes.Structisaspecialkindofcustomizedtype-therearemorecustomizedtypes.

Usethefollowingformattodefineacustomizedtype.

typetypeNametypeLiteral

Examplesofcustomizedtypes:

typeagesint

typemoneyfloat32

typemonthsmap[string]int

m:=months{

"January":31,

"February":28,

...

"December":31,

}

Ihopethatyouknowhowtousecustomizedtypesnow.SimilartotypedefinC,weuseagestosubstituteintintheaboveexample.

Let'sgetbacktotalkingaboutmethod.

Youcanuseasmanymethodsincustomtypesasyouwant.

packagemain

import"fmt"

const(

WHITE=iota

BLACK

BLUE

RED

YELLOW

)

typeColorbyte

Object-oriented

51

Page 52: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

typeBoxstruct{

width,height,depthfloat64

colorColor

}

typeBoxList[]Box//asliceofboxes

func(bBox)Volume()float64{

returnb.width*b.height*b.depth

}

func(b*Box)SetColor(cColor){

b.color=c

}

func(blBoxList)BiggestsColor()Color{

v:=0.00

k:=Color(WHITE)

for_,b:=rangebl{

ifb.Volume()>v{

v=b.Volume()

k=b.color

}

}

returnk

}

func(blBoxList)PaintItBlack(){

fori,_:=rangebl{

bl[i].SetColor(BLACK)

}

}

func(cColor)String()string{

strings:=[]string{"WHITE","BLACK","BLUE","RED","YELLOW"}

returnstrings[c]

}

funcmain(){

boxes:=BoxList{

Box{4,4,4,RED},

Box{10,10,1,YELLOW},

Box{1,1,20,BLACK},

Box{10,10,1,BLUE},

Box{10,30,1,WHITE},

Box{20,20,20,YELLOW},

}

fmt.Printf("Wehave%dboxesinourset\n",len(boxes))

fmt.Println("Thevolumeofthefirstoneis",boxes[0].Volume(),"cm³")

fmt.Println("Thecolorofthelastoneis",boxes[len(boxes)-1].color.String())

fmt.Println("Thebiggestoneis",boxes.BiggestsColor().String())

Object-oriented

52

Page 53: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

fmt.Println("Let'spaintthemallblack")

boxes.PaintItBlack()

fmt.Println("Thecolorofthesecondoneis",boxes[1].color.String())

fmt.Println("Obviously,now,thebiggestoneis",boxes.BiggestsColor().String())

}

Wedefinesomeconstantsandcustomizedtypes.

UseColorasaliasofbyte.DefineastructBoxwhichhasfieldsheight,width,lengthandcolor.DefineastructBoxListwhichhasBoxasitsfield.

Thenwedefinedsomemethodsforourcustomizedtypes.

Volume()usesBoxasitsreceiverandreturnsthevolumeofBox.SetColor(cColor)changesBox'scolor.BiggestsColor()returnsthecolorwhichhasthebiggestvolume.PaintItBlack()setscolorforallBoxinBoxListtoblack.String()useColorasitsreceiver,returnsthestringformatofcolorname.

Isitmuchclearerwhenweusewordstodescribeourrequirements?Weoftenwriteourrequirementsbeforewestartcoding.

Usepointerasreceiver

Let'stakealookatSetColormethod.ItsreceiverisapointerofBox.Yes,youcanuse*Boxasareceiver.Whydoweuseapointerhere?BecausewewanttochangeBox'scolorinthismethod.Thus,ifwedon'tuseapointer,itwillonlychangethevalueinsideacopyofBox.

Ifweseethatareceiveristhefirstargumentofamethod,it'snothardtounderstandhowitworks.

Youmightbeaskingwhywearen'tusing(*b).Color=cinsteadofb.Color=cintheSetColor()method.EitheroneisOKherebecauseGoknowshowtointerprettheassignment.DoyouthinkGoismorefascinatingnow?

Youmayalsobeaskingwhetherweshoulduse(&bl[i]).SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColor.Again,eitheroneisOKbecauseGoknowshowtointerpretit!

Inheritanceofmethod

Object-oriented

53

Page 54: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Welearnedaboutinheritanceoffieldsinthelastsection.Similarly,wealsohavemethodinheritanceinGo.Ifananonymousfieldhasmethods,thenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell.

packagemain

import"fmt"

typeHumanstruct{

namestring

ageint

phonestring

}

typeStudentstruct{

Human//anonymousfield

schoolstring

}

typeEmployeestruct{

Human

companystring

}

//defineamethodinHuman

func(h*Human)SayHi(){

fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)

}

funcmain(){

mark:=Student{Human{"Mark",25,"222-222-YYYY"},"MIT"}

sam:=Employee{Human{"Sam",45,"111-888-XXXX"},"GolangInc"}

mark.SayHi()

sam.SayHi()

}

Methodoverload

IfwewantEmployeetohaveitsownmethodSayHi,wecandefineamethodthathasthesamenameinEmployee,anditwillhideSayHiinHumanwhenwecallit.

Object-oriented

54

Page 55: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import"fmt"

typeHumanstruct{

namestring

ageint

phonestring

}

typeStudentstruct{

Human

schoolstring

}

typeEmployeestruct{

Human

companystring

}

func(h*Human)SayHi(){

fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)

}

func(e*Employee)SayHi(){

fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,

e.company,e.phone)//Yesyoucansplitinto2lineshere.

}

funcmain(){

mark:=Student{Human{"Mark",25,"222-222-YYYY"},"MIT"}

sam:=Employee{Human{"Sam",45,"111-888-XXXX"},"GolangInc"}

mark.SayHi()

sam.SayHi()

}

YouareabletowriteanObject-orientedprogramnow,andmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell.

Object-oriented

55

Page 56: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

2.6Interface

InterfaceOneofthesubtlestdesignfeaturesinGoareinterfaces.Afterreadingthissection,youwilllikelybeimpressedbytheirimplementation.

Whatisaninterface

Inshort,aninterfaceisasetofmethodsthatweusetodefineasetofactions.

Liketheexamplesinprevioussections,bothStudentandEmployeecanSayHi(),buttheydon'tdothesamething.

Let'sdosomemorework.We'lladdonemoremethodSing()tothem,alongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee.

Now,StudenthasthreemethodscalledSayHi(),Sing()andBorrowMoney(),andEmployeehasSayHi(),Sing()andSpendSalary().

ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployee.So,StudentandEmployeeimplementtheinterface:SayHi()andSing().Atthesametime,Employeedoesn'timplementtheinterface:SayHi(),Sing(),BorrowMoney(),andStudentdoesn'timplementtheinterface:SayHi(),Sing(),SpendSalary().ThisisbecauseEmployeedoesn'thavethemethodBorrowMoney()andStudentdoesn'thavethemethodSpendSalary().

TypeofInterface

Aninterfacedefinesasetofmethods,soifatypeimplementsallthemethodswesaythatitimplementstheinterface.

typeHumanstruct{

namestring

ageint

phonestring

}

typeStudentstruct{

Human

schoolstring

loanfloat32

interface

56

Page 57: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

}

typeEmployeestruct{

Human

companystring

moneyfloat32

}

func(h*Human)SayHi(){

fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)

}

func(h*Human)Sing(lyricsstring){

fmt.Println("Lala,lalala,lalalalala...",lyrics)

}

func(h*Human)Guzzle(beerSteinstring){

fmt.Println("GuzzleGuzzleGuzzle...",beerStein)

}

//EmployeeoverloadsSayhi

func(e*Employee)SayHi(){

fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,

e.company,e.phone)//Yesyoucansplitinto2lineshere.

}

func(s*Student)BorrowMoney(amountfloat32){

s.loan+=amount//(againandagainand...)

}

func(e*Employee)SpendSalary(amountfloat32){

e.money-=amount//Morevodkaplease!!!Getmethroughtheday!

}

//defineinterface

typeMeninterface{

SayHi()

Sing(lyricsstring)

Guzzle(beerSteinstring)

}

typeYoungChapinterface{

SayHi()

Sing(songstring)

BorrowMoney(amountfloat32)

}

typeElderlyGentinterface{

SayHi()

Sing(songstring)

SpendSalary(amountfloat32)

}

interface

57

Page 58: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Weknowthataninterfacecanbeimplementedbyanytype,andonetypecanimplementmanyinterfacessimultaneously.

Notethatanytypeimplementstheemptyinterfaceinterface{}becauseitdoesn'thaveanymethodsandalltypeshavezeromethodsbydefault.

Valueofinterface

Sowhatkindofvaluescanbeputintheinterface?Ifwedefineavariableasatypeinterface,anytypethatimplementstheinterfacecanassignedtothisvariable.

Liketheaboveexample,ifwedefineavariable"m"asinterfaceMen,thenanyoneofStudent,HumanorEmployeecanbeassignedto"m".SowecouldhaveasliceofMen,andanytypethatimplementsinterfaceMencanassigntothisslice.Beawarehoweverthatthesliceofinterfacedoesn'thavethesamebehaviorasasliceofothertypes.

packagemain

import"fmt"

typeHumanstruct{

namestring

ageint

phonestring

}

typeStudentstruct{

Human

schoolstring

loanfloat32

}

typeEmployeestruct{

Human

companystring

moneyfloat32

}

func(hHuman)SayHi(){

fmt.Printf("Hi,Iam%syoucancallmeon%s\n",h.name,h.phone)

}

func(hHuman)Sing(lyricsstring){

fmt.Println("Lalalala...",lyrics)

}

func(eEmployee)SayHi(){

fmt.Printf("Hi,Iam%s,Iworkat%s.Callmeon%s\n",e.name,

e.company,e.phone)//Yesyoucansplitinto2lineshere.

interface

58

Page 59: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

}

//InterfaceMenimplementedbyHuman,StudentandEmployee

typeMeninterface{

SayHi()

Sing(lyricsstring)

}

funcmain(){

mike:=Student{Human{"Mike",25,"222-222-XXX"},"MIT",0.00}

paul:=Student{Human{"Paul",26,"111-222-XXX"},"Harvard",100}

sam:=Employee{Human{"Sam",36,"444-222-XXX"},"GolangInc.",1000}

tom:=Employee{Human{"Sam",36,"444-222-XXX"},"ThingsLtd.",5000}

//defineinterfacei

variMen

//icanstoreStudent

i=mike

fmt.Println("ThisisMike,aStudent:")

i.SayHi()

i.Sing("Novemberrain")

//icanstoreEmployee

i=tom

fmt.Println("ThisisTom,anEmployee:")

i.SayHi()

i.Sing("Borntobewild")

//sliceofMen

fmt.Println("Let'suseasliceofMenandseewhathappens")

x:=make([]Men,3)

//thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen

x[0],x[1],x[2]=paul,sam,mike

for_,value:=rangex{

value.SayHi()

}

}

Aninterfaceisasetofabstractmethods,andcanbeimplementedbynon-interfacetypes.Itcannotthereforeimplementitself.

Emptyinterface

Anemptyinterfaceisaninterfacethatdoesn'tcontainanymethods,soalltypesimplementanemptyinterface.Thisfactisveryusefulwhenwewanttostorealltypesatsomepoint,andissimilartovoid*inC.

interface

59

Page 60: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//defineaasemptyinterface

varainterface{}

variint=5

s:="Helloworld"

//acanstorevalueofanytype

a=i

a=s

Ifafunctionusesanemptyinterfaceasitsargumenttype,itcanacceptanytype;ifafunctionusesemptyinterfaceasitsreturnvaluetype,itcanreturnanytype.

Methodargumentsofaninterface

Anyvariablecanbeusedinaninterface.Sohowcanweusethisfeaturetopassanytypeofvariabletoafunction?

Forexampleweusefmt.Printlnalot,buthaveyouevernoticedthatitcanacceptanytypeofargument?Lookingattheopensourcecodeoffmt,weseethefollowingdefinition.

typeStringerinterface{

String()string

}

ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmt.Printlnasanargument.Let'sproveit.

interface

60

Page 61: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"fmt"

"strconv"

)

typeHumanstruct{

namestring

ageint

phonestring

}

//Humanimplementedfmt.Stringer

func(hHuman)String()string{

return"Name:"+h.name+",Age:"+strconv.Itoa(h.age)+"years,Contact:"+h.

phone

}

funcmain(){

Bob:=Human{"Bob",39,"000-7777-XXX"}

fmt.Println("ThisHumanis:",Bob)

}

LookingbacktotheexampleofBox,youwillfindthatColorimplementsinterfaceStringeraswell,soweareabletocustomizetheprintformat.Ifwedon'timplementthisinterface,fmt.Printlnprintsthetypewithitsdefaultformat.

fmt.Println("Thebiggestoneis",boxes.BiggestsColor().String())

fmt.Println("Thebiggestoneis",boxes.BiggestsColor())

Attention:Ifthetypeimplementedtheinterfaceerror,fmtwillcallerror(),soyoudon'thavetoimplementStringeratthispoint.

Typeofvariableinaninterface

Ifavariableisthetypethatimplementsaninterface,weknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariable.Thequestionishowcanweknowthespecifictypestoredintheinterface.TherearetwowayswhichIwillshowyou.

AssertionofComma-okpattern

Gohasthesyntaxvalue,ok:=element.(T).Thischeckstoseeifthevariableisthetypethatweexpect,where"value"isthevalueofthevariable,"ok"isavariableofbooleantype,"element"istheinterfacevariableandtheTisthetypeofassertion.

interface

61

Page 62: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Iftheelementisthetypethatweexpect,okwillbetrue,falseotherwise.

Let'suseanexampletoseemoreclearly.

packagemain

import(

"fmt"

"strconv"

)

typeElementinterface{}

typeList[]Element

typePersonstruct{

namestring

ageint

}

func(pPerson)String()string{

return"(name:"+p.name+"-age:"+strconv.Itoa(p.age)+"years)"

}

funcmain(){

list:=make(List,3)

list[0]=1//anint

list[1]="Hello"//astring

list[2]=Person{"Dennis",70}

forindex,element:=rangelist{

ifvalue,ok:=element.(int);ok{

fmt.Printf("list[%d]isanintanditsvalueis%d\n",index,value)

}elseifvalue,ok:=element.(string);ok{

fmt.Printf("list[%d]isastringanditsvalueis%s\n",index,value)

}elseifvalue,ok:=element.(Person);ok{

fmt.Printf("list[%d]isaPersonanditsvalueis%s\n",index,value)

}else{

fmt.Printf("list[%d]isofadifferenttype\n",index)

}

}

}

It'squiteeasytousethispattern,butifwehavemanytypestotest,we'dbetteruseswitch.

switchtest

Let'suseswitchtorewritetheaboveexample.

interface

62

Page 63: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"fmt"

"strconv"

)

typeElementinterface{}

typeList[]Element

typePersonstruct{

namestring

ageint

}

func(pPerson)String()string{

return"(name:"+p.name+"-age:"+strconv.Itoa(p.age)+"years)"

}

funcmain(){

list:=make(List,3)

list[0]=1//anint

list[1]="Hello"//astring

list[2]=Person{"Dennis",70}

forindex,element:=rangelist{

switchvalue:=element.(type){

caseint:

fmt.Printf("list[%d]isanintanditsvalueis%d\n",index,value)

casestring:

fmt.Printf("list[%d]isastringanditsvalueis%s\n",index,value)

casePerson:

fmt.Printf("list[%d]isaPersonanditsvalueis%s\n",index,value)

default:

fmt.Println("list[%d]isofadifferenttype",index)

}

}

}

Onethingyoushouldrememberisthatelement.(type)cannotbeusedoutsideoftheswitchbody,whichmeansinthatcaseyouhavetousethecomma-okpattern.

Embeddedinterfaces

ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntax,suchasanonymousfieldsinstruct.Notsuprisingly,wecanuseinterfacesasanonymousfieldsaswell,butwecallthemEmbeddedinterfaces.Here,wefollowthesamerulesasanonymousfields.More

interface

63

Page 64: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

specifically,ifaninterfacehasanotherinterfaceembeddedwithinit,itwillbehaveasifithasallthemethodsthattheembeddedinterfacehas.

Wecanseethatthesourcefileincontainer/heaphasthefollowingdefinition:

typeInterfaceinterface{

sort.Interface//embeddedsort.Interface

Push(xinterface{})//aPushmethodtopushelementsintotheheap

Pop()interface{}//aPopmethodthatpopselementsfromtheheap

}

Weseethatsort.Interfaceisanembeddedinterface,sotheaboveInterfacehasthethreemethodscontainedwithinthesort.Interfaceimplicitly.

typeInterfaceinterface{

//Lenisthenumberofelementsinthecollection.

Len()int

//Lessreturnswhethertheelementwithindexishouldsort

//beforetheelementwithindexj.

Less(i,jint)bool

//Swapswapstheelementswithindexesiandj.

Swap(i,jint)

}

Anotherexampleistheio.ReadWriterinpackageio.

//io.ReadWriter

typeReadWriterinterface{

Reader

Writer

}

Reflection

ReflectioninGoisusedfordetermininginformationatruntime.Weusethereflectpackage,andthisofficialarticleexplainshowreflectworksinGo.

Therearethreestepsinvolvedwhenusingreflect.First,weneedtoconvertaninterfacetoreflecttypes(reflect.Typeorreflect.Value,thisdependsonthesituation).

t:=reflect.TypeOf(i)//getmeta-dataintypei,andusettogetallelements

v:=reflect.ValueOf(i)//getactualvalueintypei,andusevtochangeitsvalue

Afterthat,wecanconvertthereflectedtypestogetthevaluesthatweneed.

interface

64

Page 65: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

varxfloat64=3.4

v:=reflect.ValueOf(x)

fmt.Println("type:",v.Type())

fmt.Println("kindisfloat64:",v.Kind()==reflect.Float64)

fmt.Println("value:",v.Float())

Finally,ifwewanttochangethevaluesofthereflectedtypes,weneedtomakeitmodifiable.Asdiscussedearlier,thereisadifferencebetweenpassbyvalueandpassbyreference.Thefollowingcodewillnotcompile.

varxfloat64=3.4

v:=reflect.ValueOf(x)

v.SetFloat(7.1)

Instead,wemustusethefollowingcodetochangethevaluesfromreflecttypes.

varxfloat64=3.4

p:=reflect.ValueOf(&x)

v:=p.Elem()

v.SetFloat(7.1)

Wehavejustdiscussedthebasicsofreflection,howeveryoumustpracticemoreinordertounderstandmore.

interface

65

Page 66: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ConcurrencyItissaidthatGoistheClanguageofthe21stcentury.Ithinktherearetworeasons:first,Goisasimplelanguage;second,concurrencyisahottopicintoday'sworld,andGosupportsthisfeatureatthelanguagelevel.

goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGo.They'resimilartothreadsbutworkdifferently.Morethanadozengoroutinesmaybeonlyhave5or6underlyingthreads.Goalsogivesyoufullsupporttosharingmemoryinyourgoroutines.Onegoroutineusuallyuses4~5KBofstackmemory.Therefore,it'snothardtorunthousandsofgoroutinesonasinglecomputer.Agoroutineismorelightweight,moreefficientandmoreconvenientthansystemthreads.

goroutinesrunonthethreadmanageratruntimeinGo.Weusethegokeywordtocreateanewgoroutine,whichisafunctionattheunderlyinglevel(main()isagoroutine).

gohello(a,b,c)

Let'sseeanexample.

packagemain

import(

"fmt"

"runtime"

)

funcsay(sstring){

fori:=0;i<5;i++{

runtime.Gosched()

fmt.Println(s)

}

}

funcmain(){

gosay("world")//createanewgoroutine

say("hello")//currentgoroutine

}

Output:

Concurrency

66

Page 67: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

hello

world

hello

world

hello

world

hello

world

hello

Weseethatit'sveryeasytouseconcurrencyinGobyusingthekeywordgo.Intheaboveexample,thesetwogoroutinessharesomememory,butwewouldbetterofffollowingthedesignrecipe:Don'tuseshareddatatocommunicate,usecommunicationtosharedata.

runtime.Gosched()meanslettheCPUexecuteothergoroutines,andcomebackatsomepoint.

Thescheduleronlyusesonethreadtorunallgoroutines,whichmeansitonlyimplementsconcurrency.IfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessing,youhavetocallruntime.GOMAXPROCS(n)tosetthenumberofcoresyouwanttouse.Ifn<1,itchangesnothing.Thisfunctionmayberemovedinthefuture,seemoredetailsaboutparallelprocessingandconcurrencyinthisarticle.

channelsgoroutinesruninthesamememoryaddressspace,soyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemory.Howdoyoucommunicatebetweendifferentgoroutines?Gousesaverygoodcommunicationmechanismcalledchannel.channelislikeatwo-waypipelineinUnixshells:usechanneltosendorreceivedata.Theonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchan.Beawarethatyouhavetousemaketocreateanewchannel.

ci:=make(chanint)

cs:=make(chanstring)

cf:=make(chaninterface{})

channelusestheoperator<-tosendorreceivedata.

ch<-v//sendvtochannelch.

v:=<-ch//receivedatafromch,andassigntov

Let'sseemoreexamples.

Concurrency

67

Page 68: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import"fmt"

funcsum(a[]int,cchanint){

total:=0

for_,v:=rangea{

total+=v

}

c<-total//sendtotaltoc

}

funcmain(){

a:=[]int{7,2,8,-9,4,0}

c:=make(chanint)

gosum(a[:len(a)/2],c)

gosum(a[len(a)/2:],c)

x,y:=<-c,<-c//receivefromc

fmt.Println(x,y,x+y)

}

Sendingandreceivingdatainchannelsblocksbydefault,soit'smucheasiertousesynchronousgoroutines.WhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannel,i.e(value:=<-ch),untilothergoroutinessenddatatothischannel.Ontheotherhand,thegoroutinewillnotcontinueuntilthedataitsendstoachannel,i.e(ch<-5),isreceived.

BufferedchannelsIintroducednon-bufferedchannelsabove.Goalsohasbufferedchannelsthatcanstoremorethanasingleelement.Forexample,ch:=make(chanbool,4),herewecreateachannelthatcanstore4booleanelements.Sointhischannel,weareabletosend4elementsintoitwithoutblocking,butthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit.

ch:=make(chantype,n)

n==0!non-buffer(block)

n>0!buffer(non-blockuntilnelementsinthechannel)

Youcantrythefollowingcodeonyourcomputerandchangesomevalues.

Concurrency

68

Page 69: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import"fmt"

funcmain(){

c:=make(chanint,2)//change2to1willhaveruntimeerror,but3isfine

c<-1

c<-2

fmt.Println(<-c)

fmt.Println(<-c)

}

RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap.

packagemain

import(

"fmt"

)

funcfibonacci(nint,cchanint){

x,y:=1,1

fori:=0;i<n;i++{

c<-x

x,y=y,x+y

}

close(c)

}

funcmain(){

c:=make(chanint,10)

gofibonacci(cap(c),c)

fori:=rangec{

fmt.Println(i)

}

}

fori:=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosed.Weusethekeywordclosetoclosethechannelinaboveexample.It'simpossibletosendorreceivedataonaclosedchannel;youcanusev,ok:=<-chtotestifachannelisclosed.Ifokreturnsfalse,itmeansthethereisnodatainthatchannelanditwasclosed.

Remembertoalwaysclosechannelsinproducersandnotinconsumers,orit'sveryeasytogetintopanicstatus.

Concurrency

69

Page 70: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Anotherthingyouneedtorememberisthatchannelsarenotlikefiles.Youdon'thavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuseless,oryouwanttoexitrangeloops.

SelectIntheaboveexamples,weonlyuseonechannel,buthowcanwedealwithmorethanonechannel?Gohasakeywordcalledselecttolistentomanychannels.

selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceive.Ifseveralchannelsarereadytouseatthesametime,selectchooseswhichtoexecuterandomly.

packagemain

import"fmt"

funcfibonacci(c,quitchanint){

x,y:=1,1

for{

select{

casec<-x:

x,y=y,x+y

case<-quit:

fmt.Println("quit")

return

}

}

}

funcmain(){

c:=make(chanint)

quit:=make(chanint)

gofunc(){

fori:=0;i<10;i++{

fmt.Println(<-c)

}

quit<-0

}()

fibonacci(c,quit)

}

selecthasadefaultcaseaswell,justlikeswitch.Whenallthechannelsarenotreadyforuse,itexecutesthedefaultcase(itdoesn'twaitforthechannelanymore).

Concurrency

70

Page 71: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

select{

casei:=<-c:

//usei

default:

//executesherewhencisblocked

}

TimeoutSometimesagoroutinebecomesblocked.Howcanweavoidthistopreventthewholeprogramfromblocking?It'ssimple,wecansetatimeoutintheselect.

funcmain(){

c:=make(chanint)

o:=make(chanbool)

gofunc(){

for{

select{

casev:=<-c:

println(v)

case<-time.After(5*time.Second):

println("timeout")

o<-true

break

}

}

}()

<-o

}

RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines.

runtime.Goexit()

Exitsthecurrentgoroutine,butdeferedfunctionswillbeexecutedasusual.

runtime.Gosched()

Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint.

runtime.NumCPU()int

ReturnsthenumberofCPUcores

Concurrency

71

Page 72: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

runtime.NumGoroutine()int

Returnsthenumberofgoroutines

runtime.GOMAXPROCS(nint)int

SetshowmanyCPUcoresyouwanttouse

Concurrency

72

Page 73: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

2.8SummaryInthischapter,wemainlyintroducedthe25Gokeywords.Let'sreviewwhattheyareandwhattheydo.

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

varandconstareusedtodefinevariablesandconstants.packageandimportareforpackageuse.funcisusedtodefinefunctionsandmethods.returnisusedtoreturnvaluesinfunctionsormethods.deferisusedtodefinedeferfunctions.goisusedtostartanewgoroutine.selectisusedtoswitchovermultiplechannelsforcommunication.interfaceisusedtodefineinterfaces.structisusedtodefinespecialcustomizedtypes.break,case,continue,for,fallthrough,else,if,switch,gotoanddefaultwereintroducedinsection2.3.chanisthetypeofchannelforcommunicationamonggoroutines.typeisusedtodefinecustomizedtypes.mapisusedtodefinemapwhichissimilartohashtablesinotherlanguages.rangeisusedforreadingdatafromslice,mapandchannel.

Ifyouunderstandhowtousethese25keywords,you'velearnedalotofGoalready.

Summary

73

Page 74: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

GoProgrammingBasics

Workspace

$GOPATHand$GOROOT$GOROOT:ThisisanenvironmentvariablewhichstoresthepathwhereyourGoinstallationispresentifyouhavecustomizedit.$GOPATH:TheGouniverseforyourmachine.TheideaisthatallyourGocodeshouldresideinadirectorytreesothecodeisn'tlyingaroundinrandomplaces.

InmostunixsystemsitisdonewithexportGOPATH=/usr/home/suraj/Go.

My$GOPATHis/usr/home/suraj/Go,ithasthefollowingstructure

pkg:Thelibrarieswhich'llbeimportedinourcode,thereisa.afilecreatedattherespectivepath.bin:ThebinaryfileofourprojectwillbeinstalledhereoncallingGoinstallintheprojectfoldersrc:Willholdtheactualcode,ifyouhaveagithubaccount,thenyoucancreateafoldertreeinsidelike

Go

srcgithub.com

thewhitetulipwsharepicsort

golang.netsourcegraph.com

bin(binaries)wsharepicsort

pkg

GotakesthisuniqueapproachsothatalltheGocodeiswellorganizedandnotthrowninahaphazardmanner.Thismakesiteasytolocatecodeforhumansandsoftwarealike.

Packages

General

74

Page 75: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Packages,inGo,arejustoneormorefile(s)whichcontainsGosourcecode.Itcanbenamedanything,butitneedstobeainafolderandeachfileinthepackageshouldhavethelinepackage<name>atthetop.Thefoldernamehastobeexactlysameasthe<name>wespecifiyineachpackagesourcefile.

Therecanbeanynumberoffilesinapackagedirectory,butonlyonefilewiththemainpackage.Whilebuildingthecode,thecompilerstartswiththemainpackage.

MVCPatterns

WhenIstartedlearningbuildingwebappsinDjango,IfirstreadabouttheMVCpattern,themodels,theviewsandwhatnot.ButthatknowledgewastobeassumedbymeandIhadnoideawhythatdecisionwasmade,alongwiththatDjangoworkslikemagic,onehastoadapttoit'squirks.HencewhileprogramminginGo,it'llbeimmenselybenefitialtogrowuptotheMVCpatternbystartingoutsmall.Thefirstappshouldentirelyresideinthemain.gofile,thenslowly,astheappgrows,itneedstobestructuredwell,sotheallthehandlersgointoaviewspackage,templatesgoinatemplatesfolder,databaserelatedentitiesgoinanotherpackage.

Learningbydoingandexperimentingisthebestway.Challengethestatusquo.

PackagenamingTheactualpackagenameisjust"views"or"views",thepackageisfoundoutbythecompilerfromit'sabsolutepathfromthe$GOPATH/srcdirectory.FortheTasksapp,itresidesin$GOPATH/src/github/thewhitetulip/Tasks,thus,mypackageswillliewithintheTasksfolder.Thismakesiteasyfordistributingthelibraries.Theoretically,onecancreateapackagedirectlyinthe$GOPATH/srcfoldertoskipoutthelongnamingconventions,butdoingsobreaksthecodedistributionviaversioncontrol.

Whenpackagesareresolved,bytheGocompiler,itfirstlooksinthestandardlibraryandthenstartslookingforthefullnameinthe$GOPATH/srcfolder.

Internaldeployment

We'llfollowthestandardpracticeandputourcodein$GOPATH/src/github.com/thewhitetulip/Tasksfolder.Whiletestingourapp,weneedadeploymentversion.IuseedTaskswhielbuildingTasks,Ihavemadeafolder~/TasksandhereIkeepthedeploymentversionofTasks,whichcontainsthebinaryversionandthestaticfiles.Everynewbuildinthesrcgetspushedinthisfolder.

General

75

Page 76: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Runningaserver

WedeploywebappsonIPaddressesonspecificports.Typicallywechoosealargeportnumberlike8000soitdoesn'taffectsomeotherapplications.Certainportsarerestrictedandneedsudoaccess,like80.

TheIPaddresswebindtheservertocanbeapublicorprivate.Publicmeansusing":8080"or"0.0.0.0:8080".Privatemeans"127.0.0.1:8080"

Publicmeansanycomputerinthesamenetworkcanaccessthewebapp.Privatemeansonlyyourcomputerwillbeabletoaccessit.

//Public

log.Fatal(http.ListenAndServe(":8080",nil))

//Private

log.Fatal(http.ListenAndServe("127.0.0.1:8080",nil))

Note:127.0.0.1

127.0.0.1,calledlocalhost,isaspecialIPaddresswhichisgiventoeverymachinetorefertoitself.itdoesn'tmatterifyouareconnectedtothenetworkornot,yourmachinewillalwayshavethisIPaddress,soifyouarewantprivacyuse127.0.0.1.

Ifyoudowantyourwebapplicationtobeaccessiblethenuse0.0.0.0.0:8080orjust:8080,whenyougivejusttheportnumber,theGolanguageassumestheIPaddressthemachineisonbutnot127.0.0.1.

General

76

Page 77: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

WebProgrammingBasicsWebserversareprogramswhichgetanHTTPrequestandsendbackanHTTPresponsetorequests,theformatoftherequestistheHTTPprotocol.

TheGolanguagehashttpsupportinit'sstandardlibraryasnet/http.

Initially,HTTPwasbuiltfortransferringplaintext,lateritallowedmultimediacontenttoo.

Whenwetypewww.github.comonourbrowser'saddressbar

1. Browseraddseitherhttps://orhttp://andatrailingforwardslash2. OurrequestbecomesHTTPGET/github.com.3. WesendouttheHTTPGETrequest4. Github'sserverswillprocesstherequestandsendbackaresponse.5. Ourbrowserwillrenderthepage.

BeforeAJAXwasinvented,youhadtorefreshthepageeachtime.WithAJAX,wecanmodifythepage'scontentswithoutrefresingthepage.

HTTPMethods

HTTPhasvariousmethodslikeGET,POST,DELETE,PUT.

GET:usedtoretrievetheURL,GET/willgetthehomepage.POST:usedtocreatedatastoredontheURL.PUT:usedtoupdatedataontheURL.DELETE:usedtodeletedataintheURL.

//Createanewcategory.

//POST/categories

//Updateanexistingcategory.

//PUT/categories/12

//Viewthedetailsofacategory.

//GET/categories/12

//Deleteanexistingcategory.

//DELETE/categories/12

Thinkofcategoriesasadocument,POSTtocreateit,GETtofetchit,PUTtoupdateit,andDELETEtodeleteit.Fordeletingatask,ratherthansendingGET/delete/1234,weshouldsendaDELETE/tasks/1234.Thus,ratherthanoverusingtheGETmethodforeverything,

WebProgrammingBasics

77

Page 78: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

wecanreallyusecontextbasedonthemethodoftherequest.

GETvsPOST

Apartfromtheirfunctionaldifferences,GETandPOSTdifferinsecurityperspectives.

GETtransfersdataviatheURL.POSTsendsdataintherequest'sbodyorpayload,butthatisn'thiddenorencryptedbydefault,butitisn'tvisibleontheURL,itiseasilyaccessibletoanyonewhoknowshowtoreadaHTTPrequest.

Securityissomethingyoubuildyourapplicationaround.Inshortthereisn'tmuchdifferencebetweenGETandPOSTwhenweconsidersecurity,bothtransferdatainplaintextGETisjustrelativelyalittlelesssecuresinceURLsareloggedbyaproxyserver/firewall/browserhistoryandthatGETrequestscanbedonebythebrowseronbehalfoftheuserwithoutconfirmation.Botsarecommonovertheinternet,botscanvisitrandomlytoeverylinkpresentinyourapplication,buttheydon'tsendrandomdatatoanyFormyouhave,orifso,veryfewbotscandothat.

Forprotectingdataofthewebapp,onehastosticktousingHTTPSandsanitizeanydatathatcomesfromtheuser.

Example

Ablogconsistsofacollectionofposts,aposthastags,iswrittenbysomeauthor,atsometimeandhassomeprimarykeytouniquelyidentifyitinourdatabaseandithasaslugwhichmeanstheURL.

Thisistheeraofsemanticweb,thusthenewbeautifulURLslike,surajblog.com/posts/welcome-the-new-year,theslugisthewelcome-the-new-year.

WhentheservergetsaHTTPGETrequestof/posts/welcome-the-new-year,it'llsearchforURLhandlersstartingwiththelistofURLhandlerswehavegiven,thenit'llfindtheclosestmatch,inourcaseit'llbe/post/,thenit'llcallthehandlerofthisURL.

Our/rootURLshouldbeattheverybottomofourlist.Becausewhileexecuting,checksaredonefromtoptobottom.

//samplehandlerdefinition

http.HandleFunc("/post/",ShowPostBySlug)

http.HandleFunc("/",ShowAllPosts)

Handlertalktothedatabase,fetchthedataandrendertemplateswhichshowupasHTMLpagesinourbrowser.

WebProgrammingBasics

78

Page 79: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Whatisatemplate?

Templatesareawaytopresentdatatotheuser.TheserverpopulatedthetemplatesandsendstheHTMLpagebacktothebrowser.Forablog,itdoesn'tmakesensetogeneratehtmlpageforeachpost.Thisiswhythereisaposttemplateandtheserverwillgetallthedetailslikecontent,title,datepublishedandpopulatetheposttemplateandreturnitbacktothebrowser.

AwebapplicationisbasicallyawayofrepresentingdatastoredinthedatabasetotheenduserusingHTTP.

Writingawebapplication:

1. Fixthedatabasestructure.2. UnderstandhowdataflowsanddecidetheURLs3. Writetemplatestocorrespondingto(almost)eachURL4. WritefunctionsinGotohandleeachURLpattern,calledhandlers.5. Handlersfetchdatafromthedatabaseandpopulatedatainthetemplates.

Notabusingtemplates

Thelogicbehindcreatingtemplateswastonottorepeatourhtmlpage.Templatesupportvariableswhichourhandlersaregoingtopopulate.Thestandardwayistohandlethebusinesslogininsidethehandlerandusetemplatesjustforrenderingthedata.Templatesaretobeusedonlyforthepresentationlogicnotthebusinesslogic.Itbecomesdifficulttomaintainapplicationswhichhavebusinesslogicinsidethetemplate.Itshouldneverbedone.

Example:Wearegoingtobuildatodolistmanagerinthisbook.Itsupportmultipleusers.

Wrongway:Fetchalltasksinthetemplateandonlyshowthoseofthecurrentuser.i.e.filterthetasksinthetemplateCorrectway:Fetchonlythetasksbelongingtothecurrentuser.i.e.filterthetasksinthehandler.

FunctionalityofourEditTaskURLwhichis/edit/<id>.

fileviews/addViews.go

WebProgrammingBasics

79

Page 80: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//EditTaskFuncisourhandlerwhichwillhandlethe/edit/<id>URL

funcEditTaskFunc(whttp.ResponseWriter,r*http.Request){

//Code

task:=db.GetTaskByID(id)

editTemplate.Execute(w,task)

//Code

}

filedb/tasks.go

funcGetTaskByID(idint)types.Context{

//Codetofetchtasksofthecurrentuser

context:=types.Context{Tasks:tasks}

returncontext

}

TheEditTaskFunctalkstothedatabasewiththeGetTaskByIDfunctionandfetchesthetasksforthecurrentuserandpopulatestheeditTemplate.

Thuswecansplitanapplicationintoviews,database,templatesandcontroller(mainpackage).

StaticFiles

Staticfilesarerequiredfortemplates,theyarealltheCSS/JS/Imageswhichweloadintoourhtmltemplates.

TheURLwillbe/static/.

Execution:

1. Wegetarequestlike/static/<filepath>2. Wegotothepublicdirectoryofourapplicationandlookfor3. Ifwegetafileofthatpaththenweservethefile,othewisesenda404error.

Thepublicfoldercontainsallyourstaticfiles.Wewillhaveatemplatesfolderonthesamefolderwherethepublicispresent.

Thereasontemplatesisaseparatefolderisthatitisaseparateentityandshouldn'tbepubliclyavailableusingthe/static/URL.

WebProgrammingBasics

80

Page 81: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

public

||--static

|||--css

|||`--styles.css

..andmore

||`--js

|||--bootstrap.min.js

||....andmore

templates

||--completed.html

||...andmore

NoteOutput

Theaboveoutputisofthetreeprogram.

WebProgrammingBasics

81

Page 82: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

BasicwebapplicationMakeafolderinyour$GOPATH/src/github.com/<yourname>/Taskssubstituteyourusernameinlieuof<yourname>.

Createafilemain.go

filemain.go

packagemain

import(

"log"

"net/http"

)

funcmain(){

PORT:="127.0.0.1:8080"

log.Fatal(http.ListenAndServe(PORT,nil))

}

Weimportthehttppackageinourapplicationwithimportnet/http.

Nowgotoyourterminalandtype

[Tasks]$gorunmain.go

Youwillnoticethattheprogramdoesn'tprintanythingbecausewetolditonlytolistenontheport.Ifwewanttousertoknowthatwearerunningaserveronthatport,weshouldprintamessagesayingso,asshowninthebelowexample.

codeexamplefile:3.1basicServer.go

Implementation

82

Page 83: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"log"

"net/http"

)

funcmain(){

PORT:=":8080"

log.Print("Runningserveron"+PORT)

log.Fatal(http.ListenAndServe(PORT,nil))

}

Wheneverwerunthis,we'llgetthebelowoutput

2016/01/0122:00:36Runningserveron:8080

Openlocalhost:8080inabrowserandyou'llgetthemessage"404pagenotfound"

Thisisbecauseasofnowwehavejuststartedaservertolistenontheport8080,butwehaven'thandledtheURL.TheHTTP404errorwillbedisplayedeachtimetheserverwon'tbeabletofigureouthowtoservetherequest.

HandlingURLs

http.HandleFunc("/complete/",ShowCompleteTasksFunc)

//ShowCompleteTasksFuncisusedtopopulatethe"/completed/"URL

funcShowCompleteTasksFunc(whttp.ResponseWriter,r*http.Request){

}

WeHandleFuncinthenet/httppackagetohandleURLs.ThefirstargumentistheURLtobehandledandthesecondparameteristhefunction.Wecandefinefunctionsinthesecondparameter,butyouareadvisedagainstit.

Thehandlerfunctionrequirestwoarguments,aResponseWriterobjectandaRequestobject.WearegoingtowritetotheResponseWriterdependingonwhatwegetintheRequestobject.

HandlerExample

WewanttowritetheURLthattheuserisvisitingonourwebapp.TheURLcanbefoundintherequestobject,r.URL.Path.

Implementation

83

Page 84: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"log"

"net/http"

)

funcmain(){

PORT:=":8080"

log.Print("Runningserveron"+PORT)

http.HandleFunc("/",CompleteTaskFunc)

log.Fatal(http.ListenAndServe(PORT,nil))

}

funcCompleteTaskFunc(whttp.ResponseWriter,r*http.Request){

w.Write([]byte(r.URL.Path))

}

Parameterizedrouting

WhenwegettheURL/tasks/124,wewanttogetthetasknumber124,wedothefollowing

//GetTaskFuncisusedtodeleteatask,

funcGetTaskFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

id:=r.URL.Path[len("/tasks/"):]

w.Write([]byte("Getthetask"+id))

}

WetakeasubstringoftheURLandremovethe/delete/partandwehavetheIDofthetask.

Thisexamplemakesuseoftheslicingconcept.Itissimple,ifPathisourstringvariablethenPath[1:]isthesubstringwhichincludeseverythingfromthefirstcharacter,indexbeingzero.

Note:Parameterizedrouting

IdeallyweshouldcheckingtheURLpathinsideourview,wearesupposedtousearouter.Forrealprojects,youshouldusearouter.Herewearelearning,sowewon'tbeusingarouter.

Servingstaticfiles

http.Handle("/static/",http.FileServer(http.Dir("public")))

Implementation

84

Page 85: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Forservingstaticfiles,weusetheFileServermethodofthehttppackage.Ittakesafolderasanargument.Makesureyougiveonlythepublicfolderpathintheargument.

Homework

Readthedocumentationofnet/http&logandgettoknowofthemethods/functionsinthepackages[1]FindouthowmanyalternativesaretheretoListenAndServe.Writeahandlertoservestaticfiles,iffileisavailableonthatpaththenitshouldservethefile,otherwiseitmustreturnanHTTP404error.Writeacommandlineapplicationtosharefiles/folderoverHTTP,thesyntaxshouldbelikethis./wshare-ffile.pdffileonlink=192.168.2.1:8080.

Footnotes

[1]:Learnhowtoreaddocumentation,itsavesalotoftime.

Implementation

85

Page 86: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

DesigningourwebappThedesignphaseisthemostimportantinanysoftwareprojectasonesmallmistakeindesigningcoststheprojectserverly.Itbecomesverycostlytofixthatlater.

Ourwebappisgoingtobeatodolistmanagerforasingleuser,soit'llhavethefollowingfeatures:

1.Abilitytoadd/delete/modifytask.

2.Abilitytomarktasksascomplete/incomplete.

3.Displaythetasksasaonecolumnlist.

4.Abilitytoswitchmodesbetweenpending/completed/deletedtasks

5.Displaynotificationslikenoteadded/deleted/archived

6.Searchfortextandhighlightthetextinthesearchresultspage.

TheDesign

TranslatingourdesigntoAPI,wegetthefollowing.

/add/POST=addnewtask

/GET=showpendingtasks

/complete/GET=showcompletedtasks

/deleted/GET=showdeletedtasks

/edit/<id>POST=editpost

/edit/<id>GET=showtheeditpage

/trash/<id>POST=trashposttorecyclebin

/delete/<id>POST=permanentlydeletepost

/complete/<id>POST=markpostascomplete

/login/POST=dothelogin

/login/GET=showloginpage

/logout/POST=logtheuserout

/restore/<id>POST=restorethattask

/update/<id>POST=updatetask

/change/GET=willallowchangingpassword

/register/GET=showtheregisterpage

/register/POST=willaddentriesintodatabase

file~/main/main.go

Designingourwebapp

86

Page 87: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"log"

"net/http"

)

funcmain(){

http.HandleFunc("/complete/",CompleteTaskFunc)

http.HandleFunc("/delete/",DeleteTaskFunc)

http.HandleFunc("/deleted/",ShowTrashTaskFunc)

http.HandleFunc("/trash/",TrashTaskFunc)

http.HandleFunc("/edit/",EditTaskFunc)

http.HandleFunc("/completed/",ShowCompleteTasksFunc)

http.HandleFunc("/restore/",RestoreTaskFunc)

http.HandleFunc("/add/",AddTaskFunc)

http.HandleFunc("/update/",UpdateTaskFunc)

http.HandleFunc("/search/",SearchTaskFunc)

http.HandleFunc("/login",GetLogin)

http.HandleFunc("/register",PostRegister)

http.HandleFunc("/admin",HandleAdmin)

http.HandleFunc("/add_user",PostAddUser)

http.HandleFunc("/change",PostChange)

http.HandleFunc("/logout",HandleLogout)

http.HandleFunc("/",ShowAllTasksFunc)

http.Handle("/static/",http.FileServer(http.Dir("public")))

log.Print("runningonport8080")

log.Fatal(http.ListenAndServe(":8080",nil))

}

Createallfunctionswementionedaboveandmakethenecessarychangesasperonedefinitionthatweshowbelowinthisfile.

funcShowAllTasksFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

message:="allpendingtasksGET"

}else{

message:="allpendingtasksPOST"

}

w.Write([]byte(message))

}

Afteryoucreatethesefunctionsruntheserverasbelow,

[Tasks]$gobuild

[Tasks]$./Tasks

Designingourwebapp

87

Page 88: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Inyourbrowsertypelocalhost:8080andtypealltheseURLsandseewhatmessageyouget.

Homework

Checkthedocumentationforhttp.ResponseWriterandhttp.Requestobjectsandgettoknowallthevariables/functions/constantsforhttppackageandthesetwowhichwementioned

Designingourwebapp

88

Page 89: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

UsingdatabasesinGoGodoesn'tprovideoutoftheboxsupportforanydatabase,butitprovidesaninterface,whichcanbeusedbydatabaselibrarycreatorstokeepallthedatabaselibrariescompatiblewitheachother.

Wewillusesqliteforthisbook.

Creatingandconfiguringdatabase

UsethisDDLtocreateatableinourdatabase

[Tasks]$sqlite3tasks.db

SQLiteversion3.8.22013-12-0614:53:30

Enter".help"forinstructions

EnterSQLstatementsterminatedwitha";"

sqlite>CREATETABLEtask(

idintegerprimarykeyautoincrement,

titlevarchar(100),

contenttext,

is_deletedchar(1)default'N',

created_datetimestamp,

last_modified_attimestamp,

finish_datetimestamp

);

Usethefollowinginsertstatementstoenterdatainourtable,sowe'llbeginreadingdatainourShowAllTasksfunctionwhichwewroteinthepreviouschapter

DatabaseHandling

89

Page 90: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

INSERTINTO"task"VALUES(1,'Publishongithub',

'Publishthesourceoftasksandpicsortongithub',

'N','2015-11-1215:30:59','2015-11-2114:19:22',

'2015-11-1717:02:18');

INSERTINTO"task"VALUES(4,'gofmtall',

'Theideaistorungofmt-wfile.goonevery

gofileinthelisting,*Editturnsoutthisisisdifficult

todoingolang**Editbarely3linebashscript:P'

,'N','2015-11-1216:58:31',

'2015-11-1410:42:14','2015-11-1313:16:48');

INSERTINTO"task"VALUES(7,'modificationstotask',

'1.addsearchfunction#Done

2.apriorityfeaturetotask

3.commentsontasks

4.Duedate

5.removedependencyonhttprouter#Done',

'N','2015-11-1304:23:27','2015-11-1304:23:27',NULL);

Installingthesqlitedriverforgo

We'llusethego-sqlite3drivercreatedbymattn.Thereasonbeingitimplementsthedatabase/sqlinterface.Typethisinyourterminal:

goget"github.com/mattn/go-sqlite3"

Accessingdatabaseingo

Weimportthelibraryasimport_"github.com/mattn/go-sqlite3"

Thepackageisimportedanonymously,whenweimportnet/httpwehavetousehttp.toaccessthepackage.Tobeabletoswapunderlyingdatabases,wewon'tdothat.Thustheanonymouspackageimport.

Underthehood,thedriverregistersitselftothedatabase/sqlpackage.

NoteThe'_'operator

The_operatorhasauniqueroleingo,itisusedtodenoteanemptyvariable,usedwhenwewanttoignoredata.numsisanarray,whileweloopthrougharraysusingrangeitreturnsa(key,value)pair.hereweignorethekeyandprintthevalue.

DatabaseHandling

90

Page 91: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

for_,value:=rangenums{

fmt.Println(value)

}

Alsonotethatwecangiveapackagealiasinsteadoftheunderscorecharactershouldwewantanaliasforourpackage.

Everydatabasehasaconnectionmechanism,fileforsqliteandIPaddressforMySQL/Postgres.

Weencapsulateourdbobjectinsideastruct.Wealsoencapsulatethedatabaseactionsasshownbelow

vardatabaseDatabase

//Databaseencapsulatesdatabase

typeDatabasestruct{

db*sql.DB

}

func(dbDatabase)begin()(tx*sql.Tx){

tx,err:=db.db.Begin()

iferr!=nil{

log.Println(err)

returnnil

}

returntx

}

func(dbDatabase)prepare(qstring)(stmt*sql.Stmt){

stmt,err:=db.db.Prepare(q)

iferr!=nil{

log.Println(err)

returnnil

}

returnstmt

}

func(dbDatabase)query(qstring,

args...interface{})(rows*sql.Rows){

rows,err:=db.db.Query(q,args...)

iferr!=nil{

log.Println(err)

returnnil

}

returnrows

}

funcinit(){

database.db,err=

DatabaseHandling

91

Page 92: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

sql.Open("sqlite3","./newtask.db")

iferr!=nil{

log.Fatal(err)

}

}

//Closedatabaseconnection

funcClose(){

database.db.Close()

}

//taskQueryencapsulatesExec()

functaskQuery(sqlstring,args...interface{})error{

SQL:=database.prepare(sql)

tx:=database.begin()

_,err=tx.Stmt(SQL).Exec(args...)

iferr!=nil{

log.Println("taskQuery:",err)

tx.Rollback()

}else{

tx.Commit()

}

returnerr

}

Noteinit()

Theinitfunctionisthefirstfunctiontorunwhenthepackageisimportedorexecuted.Thisiswhywedotheinitializationinit.

NoteDBfromgodoc

typeDBstruct{

//containsfilteredorunexportedfields

}

DBisadatabasehandlerepresentingapoolofzeroormoreunderlyingconnections.It'ssafeforconcurrentusebymultiplegoroutines.

Thesqlpackagecreatesandfreesconnectionsautomatically;italsomaintainsafreepoolofidleconnections.Ifthedatabasehasaconceptofper-connectionstate,suchstatecanonlybereliablyobservedwithinatransaction.Wedonotwantthisvariabletobeaccessiblefromoutsidethepackagesoitisunexported.Openmayjustvalidateitsargumentswithoutcreatingaconnectiontothedatabase.Toverifythatthedatasourcenameisvalid,callPing().ThereturnedDBissafeforconcurrentusebymultiplegoroutinesandmaintainsitsownpoolofidleconnections.Thus,theOpenfunctionshouldbecalledjustonce.ItisrarelynecessarytocloseaDB.

DatabaseHandling

92

Page 93: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

err=db.Ping()

iferr!=nil{

//dosomethingaboutit

}

Thesql.DBobjectshoudn'tbeopenedandclosedfrequently,itshouldbeclosedonlywhenwenolongerneedtoaccessthedatabase.

Pleaserefertothedocumentationofdatabase/sqlformoredetails.

Noteexportedandunexportedvariables

Exported:variablestartswithacapitalletterandisaccessibleforthosewhoimportthispackageUnexported:variableisprivateforthepackage,notaccessibleoutsideit'sdeclaration.

Queryingthedatabase

Statementsthatdon’treturnrowsshouldnotuseQueryfunctions;theyshoulduseExec().

Fromthegodocumentation

func(*DB)Exec

func(db*DB)Exec(querystring,args...interface{})(Result,error)

Execexecutesaquerywithoutreturninganyrows.Theargsareforany

placeholderparametersinthequery.

WeusetheQuerymethodtoquerythedatabasewhenweexpectsomeresultfromthedatabase.

DatabaseHandling

93

Page 94: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

getTaskSQL="selectid,title,content,created_datefromtask

wherefinish_dateisnullandis_deleted='N'orderbycreated_dateasc"

rows,err:=database.Query(getTaskSQL)

iferr!=nil{

log.Println(err)

}

deferrows.Close()

forrows.Next(){

err:=rows.Scan(&TaskID,&TaskTitle,&TaskContent,&TaskCreated)

TaskContent=strings.Replace(TaskContent,"\n","<br>",-1)

iferr!=nil{

log.Println(err)

}

fmt.Println(TaskID,TaskTitle,TaskContent,TaskCreated)

}

taskSQL:="deletefromtask"

tx:=database.begin()

_,err=tx.Stmt(SQL).Exec(args...)

iferr!=nil{

tx.Rollback()

}else{

tx.Commit()

}

Notedeferkeyword

Weusedeferinsideafunctioncall.

packagemain

import(

"fmt"

"io/ioutil"

"os"

)

funcmain(){

file,err:=os.Open('file.dat')

iferr!=nil{

fmt.Println("Filedoesn'texistoryoudon'thave

readpermission")

}

deferfile.Close()

inputReader:=bufio.NewReader(file)

//dosomethingaboutinputReader

}

DatabaseHandling

94

Page 95: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thedeferstatementputsthefunctioncallatthebottomofthecallstack,sowheneverthefunctionreturns,deferistriggered.Onehastobecarefulwithusingdefer,itcancausedifficulttofindbugs.

file~/main/main.go

Findandfixthebug:

packagemain

import(

_"github.com/mattn/go-sqlite3"

"fmt"

)

vardatabase*sql.DB

funcinit(){

deferdatabase.Close()

database,err=sql.Open("sqlite3","./tasks.db")

iferr!=nil{

fmt.Println(err)

}

}

//intentionalbugexists,fixit

funcmain(){

getTaskSQL="selectid,title,content,created_datefromtask

wherefinish_dateisnullandis_deleted='N'orderbycreated_dateasc"

rows,err:=database.Query(getTaskSQL)

iferr!=nil{

fmt.Println(err)

}

deferrows.Close()

forrows.Next(){

err:=rows.Scan(&TaskID,&TaskTitle,&TaskContent,&TaskCreated)

TaskContent=strings.Replace(TaskContent,"\n","<br>",-1)

iferr!=nil{

fmt.Println(err)

}

fmt.Println(TaskID,TaskTitle,TaskContent,TaskCreated)

}

err=rows.Err()

iferr!=nil{

log.Fatal(err)

}

}

Alwaysdeferrows.Close(),tofreethedatabaseconnectioninthepool.Solongasrowscontainstheresultset,thedatabaseconnectionisinuseandnotavailableintheconnectionpool.

DatabaseHandling

95

Page 96: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Whentherows.Next()functionreturnsEOF(EndofFile),whichmeansthatithasreachedtheendofrecords,it'llcallrows.Close()foryou,Close()canbecalledmultipletimeswithoutsideeffects.

Single-RowQueries

Ifaqueryreturnsatmostonerow,youcanuseashortcut:

vartaskDescriptionstring

query:="selecttaskDescriptionfromtaskwhereid=?"

err=db.QueryRow(query,1).Scan(&taskDescription)

iferr!=nil{

log.Fatal(err)

}

fmt.Println(taskDescription)

ErrorsfromthequeryaredeferreduntilScan()iscalled,andthenarereturnedfromthat.YoucanalsocallQueryRow()onapreparedstatement:

query:="selecttaskDescriptionfromtaskwhereid=?"

stmt,err:=db.Prepare(query,1).Scan(&taskDescription)

iferr!=nil{

log.Fatal(err)

}

...

vartaskDescriptionstring

err=stmt.QueryRow(1).Scan(&taskDescription)

iferr!=nil{

log.Fatal(err)

}

fmt.Println(taskDescription)

Writingdataintothedatabase

Abovefunctionsfetcheddatafromthedatabase,transactionsaretobeusedtowritedatainthedatabase.

Belowliesanexampleofusingtransaction

filedb/db.go

DatabaseHandling

96

Page 97: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//RestoreTaskisusedtorestoretasksfromtheTrash

funcRestoreTask(idint)error{

query:="updatetasksetis_deleted='N',last_modified_at=datetime()whereid=?"

restoreSQL,err:=database.Prepare(query)

iferr!=nil{

fmt.Println(err)

}

tx,err:=database.Begin()

iferr!=nil{

fmt.Println(err)

}

_,err=tx.Stmt(restoreSQL).Exec(id)

iferr!=nil{

fmt.Println("doingrollback")

tx.Rollback()

}else{

tx.Commit()

}

returnerr

}

Prepare

Preparecreatesapreparedstatementforlaterqueriesorexecutions.Multiplequeriesorexecutionsmayberunconcurrentlyfromthereturnedstatement.Thecallermustcallthestatement'sClosemethodwhenthestatementisnolongerneeded.

NoteErrorhandling

BecauseofGo'suniquemethodofhandlingerrors,wecanbestuckintheiferr!=nilland.But,ontheotherhanditsimplifieserrorhandlingaswejusthavetoreturntheerrormessage.

AnexcellentresourceaboutGoanddatabasescanbefoundathttp://go-database-sql.org

Thefaultinourcode:

Fixingtheintentionalbugintheabovecode:

funcinit(){

deferdatabase.Close()

database,err=sql.Open("sqlite3","./tasks.db")

iferr!=nil{

fmt.Println(err)

}

}

DatabaseHandling

97

Page 98: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Homework

Seethe/code/chapter-4/4.5databaseinourcoderepositoryandmodifythefiletoinsertdatafromthe4.3formsuploadfolder.Wehavetwoworkingcodeset,oneofprintingformvaluesontheconsoleandoneoffetchingdbvaluesandrenderingatemplate.Whatyouhavetodoisbasedonthischapter,writemethodstoinsertvaluesfromtheformtothedatabase.

DatabaseHandling

98

Page 99: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

AnExampleExpectedoutput:

openyourtask.dbfileinsqlite3likethis

[Tasks]$sqlite3task.db

sqlite>selecttitlefromtasklimit1;

Publishongithub

Nowthisoutputshouldmatchwiththeoneweseeatlocalhost:8080

Afterrunningthefile,gotolocalhost:8080andlocalhost:8080/add

file~/main/main.go

packagemain

import(

"database/sql"

"fmt"

_"github.com/mattn/go-sqlite3"

"log"

"net/http"

"time"

)

vardatabase*sql.DB

varerrerror

//Taskisthestructusedtoidentifytasks

typeTaskstruct{

Idint

Titlestring

Contentstring

Createdstring

}

//Contextisthestructpassedtotemplates

typeContextstruct{

Tasks[]Task

Navigationstring

Searchstring

Messagestring

}

funcinit(){

WebappExample

99

Page 100: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

database,err=sql.Open("sqlite3","./tasks.db")

iferr!=nil{

fmt.Println(err)

}

}

funcmain(){

http.HandleFunc("/",ShowAllTasksFunc)

http.HandleFunc("/add/",AddTaskFunc)

fmt.Println("runningon8080")

log.Fatal(http.ListenAndServe(":8080",nil))

}

//ShowAllTasksFuncisusedtohandlethe"/"URLwhichisthedefaultone

funcShowAllTasksFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

context:=GetTasks()//truewhenyouwantnondeletednotes

w.Write([]byte(context.Tasks[0].Title))

}else{

http.Redirect(w,r,"/",http.StatusFound)

}

}

funcGetTasks()Context{

vartask[]Task

varcontextContext

varTaskIDint

varTaskTitlestring

varTaskContentstring

varTaskCreatedtime.Time

vargetTasksqlstring

getTasksql="selectid,title,content,created_datefromtask;"

rows,err:=database.Query(getTasksql)

iferr!=nil{

fmt.Println(err)

}

deferrows.Close()

forrows.Next(){

err:=rows.Scan(&TaskID,&TaskTitle,&TaskContent,&TaskCreated)

iferr!=nil{

fmt.Println(err)

}

TaskCreated=TaskCreated.Local()

a:=Task{Id:TaskID,Title:TaskTitle,Content:TaskContent,

Created:TaskCreated.Format(time.UnixDate)[0:20]}

task=append(task,a)

}

context=Context{Tasks:task}

returncontext

}

WebappExample

100

Page 101: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//AddTaskFuncisusedtohandletheadditionofnewtask,"/add"URL

funcAddTaskFunc(whttp.ResponseWriter,r*http.Request){

title:="randomtitle"

content:="randomcontent"

truth:=AddTask(title,content)

iftruth!=nil{

log.Fatal("Erroraddingtask")

}

w.Write([]byte("Addedtask"))

}

//AddTaskisusedtoaddthetaskinthedatabase

funcAddTask(title,contentstring)error{

query:="insertintotask(title,content,created_date,last_modified_at)\

values(?,?,datetime(),datetime())"

restoreSQL,err:=database.Prepare(query)

iferr!=nil{

fmt.Println(err)

}

tx,err:=database.Begin()

_,err=tx.Stmt(restoreSQL).Exec(title,content)

iferr!=nil{

fmt.Println(err)

tx.Rollback()

}else{

log.Print("insertsuccessful")

tx.Commit()

}

returnerr

}

HomeworkThehomeworkistosplitthecodeintopackagesandgetittowork,thetypedefinitiongoesintothetypes/types.gofile,thehandlerdefinitiongoesintotheviews/views.go,thedatabasereadandwritemethodsgointothedb/db.go.Makesurethatafteryourefactorthecode,thatthecoderuns.

WebappExample

101

Page 102: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

WorkingwithFormsHTMLformsareusedtogetdatafromtheuser.FormscanuseboththeGETandPOSTmethodsfortransferringdatatotheserver,butitisrecommendedtouseHTTPPOSTmethodjustbecauseitdoesn'thighlightdataintheURLandbecauseofthemanythingswediscussedinthechapterWebProgrammingBasics.

Formsarerenderedbytemplating,whichwe'llseeinalaterchapter.Asofnowwewanttounderstandhowtogetdatafromtheenduserbyusingforms.

Therearetwopartsofworkingwithforms,theHTMLpartandtheGopart.TheHTMLpagegetsthedataandsendsittotheserverasaPOST/GETandtheGopartwillparsetheformtodosometasklikelettingtheusertologinorinsertingdatainthedatabase.

Eachformelementhasanamewhichisreferencedintheserversidepartoftheform,belowwehavethefileuploadandadropdownlist.Bothofwhichhaveauniquename.

<formaction="/add/"method="POST">

<divclass="form-group">

<inputtype="text"name="title"class="form-control"id="add-note-title"place

holder="Title"

style="border:none;border-bottom:1pxsolidgray;box-shadow:none;">

</div>

<divclass="form-group">

<textareaclass="form-control"name="content"id="add-note-content"placeholde

r="Content"

rows="10"style="border:none;border-bottom:1pxsolidgray;box-shadow:none;"><

/textarea>

File:<inputtype="file"name="uploadfile"/><br>

Priority:<selectname="priority">

<option>---</option>

<optionvalue="3">High</option>

<optionvalue="2">Medium</option>

<optionvalue="1">Low</option>

</select>

</div>

</div>

<divclass="modal-footer">

<buttontype="button"class="btnbtn-default"data-dismiss="modal">Close</butt

on>

<inputtype="submit"text="submit"class="btnbtn-default"/>

</div>

</form>

Formhandling

102

Page 103: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

WhenwearepopulatingthisHTMLpage,wecanalsopopulateitdynamically,withoutgettingboggeddownbysyntax,ignoretemplatingforthewhileWehaveavariablecalledNavigationandonecalledCategories,weloopthroughCategoriesandiftheNavigationisequaltothatcategorythenthecheckedvalueistrue.

Category:

<selectname="category"class="dropdown">

<option>---</option>

{{$navigation:=.Navigation}}{{$categories:=.Categories}}

{{range$cat:=$categories}}

<optionvalue="{{$cat.Name}}"{{ifeq$cat.Name$navigation}}checked="checke

d"{{end}}>{{$cat.Name}}</option>

{{end}}

</select>

Herewehaveusedadropdownbox,youcanuseradiobuttonslikebelow

<inputtype="radio"name="gender"value="1">Female

<inputtype="radio"name="gender"value="2">Male

<inputtype="radio"name="gender"value="3">Other

Orcheckboxes

<inputtype="checkbox"name="gender"value="female">Female

<inputtype="checkbox"name="gender"value="male">Male

<inputtype="checkbox"name="gender"value="other">Other

Wegetthevalueofadropdownbox/radiobutton/checkboxontheserversidebyusingthenamefieldlikebelow:

value:=r.Form.Get("gender")

value:=r.FormValue("gender")

Aswesawearlier,ourwebserversbasicallytakeaHTTPRequestobjectandreturnanHTTPResponseObject,belowisanexampleofasampleHTTPRequestobject.

ThehostistheIPaddresssendingthereq,UserAgent:fingerprintofthemachine,theAccept-fieldsdefinevariouspartslikethelanguage,encodingRefereriswhichIPmadethecall,CookieisthevalueofthecookiestoredonthesystemandConnectionisthetypeofconnection.

Inthisrequestsnapshot,wealsohaveafilewhichweupload,forfileupload,thecontenttypeismultipart/form-data

Formhandling

103

Page 104: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

RequestHeader

Host:127.0.0.1:8081

User-Agent:...

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language:en-US,en;q=0.5

Accept-Encoding:gzip,deflate

DNT:1

Referer:http://127.0.0.1:8081/

Cookie:csrftoken=abcd

Connection:keep-alive

RequestBody

Content-Type:multipart/form-data;

boundary=---------------------------6299264802312704731507948053

Content-Length:15031

-----------------------------6299264802312704731507948053

Content-Disposition:form-data;name="title"

workingwithforms

-----------------------------6299264802312704731507948053

Content-Disposition:form-data;name="CSRFToken"

abcd

-----------------------------6299264802312704731507948053

Content-Disposition:form-data;name="content"

finishthechapterworkingwithforms

-----------------------------6299264802312704731507948053

Content-Disposition:form-data;name="uploadfile";filename="2.4workingwithform.md"

Content-Type:text/x-markdown

--filecontent--

-----------------------------6299264802312704731507948053

Content-Disposition:form-data;name="priority"

3

-----------------------------6299264802312704731507948053--

IfyouhadwonderedhowGoogle'shomepageshowsapopupwhenyouvisitgoogle.comonIEofFirefox,itchecksyourUser-Agent.ThethingwithHTTPrequestisthattheycanbemodifiedtoanyextent,theChromedevelopertoolsgivesyouquitesophisticatedtoolstomodifyyourrequests,evenUserAgentspoofingisadefaultfeatureavaiable,thisfeatureisavailablesowecantestourwebappsinonewindowsimulatingmanyinternetbrowsersatonego.

Formhandling

104

Page 105: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thebasicpartofworkingwithformsistoidentifywhichuserthatparticularformbelongsto,therearewaystoattainthat,wecaneitherhaveastatefulorastatelesswebserver.

Astatelessserverdoesn'tstoresessions,itrequiresanauthenticationkeyforeachrequestwhileastatefulserverstoressessions.Forstoringsessionsacookieisused,whichisafilewhichisstoredintheprivatememoryofthewebbrowserwhichweuse.Onlythewebsitewhichcreatedthecookiecanaccessthecookie,nothirdpartywebsitescanaccessthecookies,buttheOSusercanread/edit/deletecookiesusingthewebbrowser.

CSRF

CSRFstandsforCrossRequestSiteForgery.AnywebsitecansendaPOSTrequesttoyourwebserver,whosenttherequestcanbefoundintheRefererfieldofyourHTTPresponse.Itisaformofconfuseddeputyattackinwhichthedeputyisyourwebbrowser.Amalicioususerdoesn'thavedirectaccesstoyourwebsite,soitmakesuseofyourbrowsertosendamaliciousrequest.Typicallycookiesenableyourbrowsertoauthenticateitselftoawebserver,sowhatthesemaliciouswebsitesdois,theysendinaHTTPrequestonbehalfofyourbrowser.

Wecanthwartthisattackbyrestrictingthereferertoyourowndomain,butitisquiteeasytomanipulatethemisspeltrefererfieldofaHTTPrequest.

Anotherwayistousetokens.Whilerenderingourform,wesendinahiddenfieldwithcryptogeneratedstringof256characters,sowhenweprocessthePOSTrequest,wefirstcheckifthetokenisvalidornotandthendecideifthedatacamefromagenuinesourceorfromamalicioussource.Itdoesn'thavetobemaliciousactually,evenifalegitimateusertriedtotrickyourwebserverintoacceptingdata,weshouldn'tentertainit.

Tocheckthecsrftoken,weservethetokentotheformandstoreitinacookie,whenwegetthePOSTrequest,wecheckifbothareequalornot.Thisisbecauseamaliciouspersonmighttrickausertoclickonaformbuttheycan'tsetcookiesforyourwebapplication.

Apointtonotehereisthatnevertrustuserdata.Alwaysclean/sanitizedatawhichyougetfromtheenduser.

NoteJavascript

Ifyouareseriousaboutwebdevelopment,yououghttolearnJavascriptindetail.Whilebuildingawebapp,therewillbetimeswhenyouwouldwanttoimprovetheUIofyourapplication,whichwouldmeanachangeinthehtmlpage.UsingJSisinevitablewhilebuildingbeautifulwebapps,whileaddingsomenewhtmlfeature,openthe"webinspector"presentinthedevelopertoolsanddynamicallyaddthehtmlcode.ThewebinspectorallowsustomanipulatetheCSSandHTMLpart.Nowopenthejavascriptconsole,thatenables

Formhandling

105

Page 106: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

youtotesttheJSfeaturewhichyouarewillingtoadd.Forinstance,inthetasksapplication,therewasnoprovisiontoexpand/contractthesizeofthetask,soIaddedabuttoninthewebinspector,

<buttonclass="toggle"></button>

IntheJSconsole,totogglethevisibilityofmy.noteContentfield,Ididthis:

$('.toggle').next().toggle()

Thisprovedthatitworks,sonowgotoyourtemplateandactuallyaddthecode.Makesurethehtmliscorrectbecausewhilerunning,thehtmlfilesareparsedonce,soforanyhtmlchange,youhavetorunthewebappforeachHTMLchange.Sooncethehtmlissetup,ifyouchangetheJS/CSSthenyoujusthavetorefreshthepage,becausethehtmlpagegetstheJS/CSSeachtimethepageisloaded.

Aswesawintheaboveparagraph,forpreventingCSRF,weneedtogenerateatokenandsendasahiddenfieldintheformandstoreitinacookie,whenwegetthePOSTrequestfromthe

FormsinGo

Inthebelowfunctionwesetthecookie,wefirstgenerateaCSRFtoken,which'llbeuniqueforeachHTTPrequestwhichwegetandstoreitinacookie.

//ShowAllTasksFuncisusedtohandlethe"/"URLwhichisthedefaultons

funcShowAllTasksFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

context:=db.GetTasks("pending")//truewhenyouwantnondeletednotes

ifmessage!=""{

context.Message=message

}

context.CSRFToken="abcd"

message=""

expiration:=time.Now().Add(365*24*time.Hour)

cookie:=http.Cookie{Name:"csrftoken",Value:"abcd",Expires:expiration}

http.SetCookie(w,&cookie)

homeTemplate.Execute(w,context)

}else{

message="Methodnotallowed"

http.Redirect(w,r,"/",http.StatusFound)

}

}

Formhandling

106

Page 107: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ThebelowhandlerhandlesthePOSTrequestsentbyourform,itfetchesthevalueofthecsrftokencookieandgetsthevalueofthehiddenCSRFTokenfieldoftheaddtaskform.Ifthevalueofthecookieisequaltothevaluefetchedbytheform,thenweallowittogotothedatabase.

ThecalltoParseFormwillparsethecontentsoftheformintoGettablefieldswhichwecanfetchusingtheGetfunction.Thiscalliscompulsory.

//AddTaskFuncisusedtohandletheadditionofnewtask,"/add"URL

funcAddTaskFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="POST"{

r.ParseForm()

file,handler,err:=r.FormFile("uploadfile")

iferr!=nil{

log.Println(err)

}

taskPriority,priorityErr:=strconv.Atoi(r.FormValue("priority"))

ifpriorityErr!=nil{

log.Print("unabletoconvertprioritytointeger")

}

priorityList:=[]int{1,2,3}

for_,priority:=rangepriorityList{

iftaskPriority!=priority{

log.Println("incorrectprioritysent")

//mightwanttologassecurityincident

taskPriority=1//thisdefaultstheprioritytolow

}

}

title:=template.HTMLEscapeString(r.Form.Get("title"))

content:=template.HTMLEscapeString(r.Form.Get("content"))

formToken:=template.HTMLEscapeString(r.Form.Get("CSRFToken"))

cookie,_:=r.Cookie("csrftoken")

ifformToken==cookie.Value{

ifhandler!=nil{

r.ParseMultipartForm(32<<20)//definedmaximumsizeoffile

deferfile.Close()

f,err:=os.OpenFile("./files/"+handler.Filename,os.O_WRONLY|os.O_CR

EATE,0666)

iferr!=nil{

log.Println(err)

return

}

deferf.Close()

io.Copy(f,file)

filelink:=

"<br><ahref=/files/"+handler.Filename+">"+handler.Filename+"

</a>"

content=content+filelink

}

Formhandling

107

Page 108: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

truth:=db.AddTask(title,content,taskPriority)

iftruth!=nil{

message="Erroraddingtask"

log.Println("erroraddingtasktodb")

}else{

message="Taskadded"

log.Println("addedtasktodb")

}

http.Redirect(w,r,"/",http.StatusFound)

}else{

log.Fatal("CSRFmismatch")

}

}else{

message="Methodnotallowed"

http.Redirect(w,r,"/",http.StatusFound)

}

}

NoteCookies

Cookieisawaytostoredataonthebrowser,HTTPisastatelessprotocol,itwasn'tbuiltforsessions,basicallytheInternetitselfwasn'tbuiltconsideringsecurityinmindsinceinitiallyitwasjustawaytosharedocumentsonline,henceHTTPisstateless,whenthewebserverreceivesrequests,itcan'tdistinguishbetweentwoconsequitiverequests,hencetheconceptofcookieswereadded,thuswhilestartingasession,wegenerateasessionIDandstoreitonthedatabaseinmemoryoronthedatabaseandwestorethesameIDonacookieonthewebbrowserandwevalidatebothofthemtoauthenticatethem.

Wehavetonotethat,ifwesetanexpirydateforacookie,thenitisstoredonthefilesystemotherwiseitisstoredinmemoryinthebrowser.Intheincognitomode,thisisthecase,allthecookiesarestoredinmemoryandnotinthefilesystem.

HTTPRequest

Host:localhost:8080

User-Agent:.....

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language:en-US,en;q=0.5

Accept-Encoding:gzip,deflate

DNT:1

Referer:http://localhost:8080/

Cookie:csrftoken=abcd

Connection:keep-alive

Cache-Control:max-age=0

Formhandling

108

Page 109: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thebrowser,whilesendingaresponseappendsallthecookiedatastoredinitsmemoryorfilealongwiththeotheraspectsoftheHTTPrequestsowecanaccessthecookieasr.Cookie,it'llcontaineverycookieforthatparticulardomain,we'dthenloopthroughittofetchthedatawhichwewant.Thisisimportantforsecurityreasons,supposeIsetacookieonmyimaginedomain.comandifitcontainsacsrftokenandifthatcookieisaccessibletosomeotherwebappthenitishorriblesincetheycanmasqueradeasanylegitmateuser.Butthisain'tpossible,sinceawebsitecanonlyaccessthecookiestoredforitsowndomain,pluswehavethefeaturetosetHTTPonlyvalueofacookieastrue,whichsaysthatevenjavascriptcan'taccessthecookies.

HTTPResponse

Content-Type:text/html;charset=utf-8

Date:Tue,12Jan201616:43:53GMT

Set-Cookie:csrftoken=abcd;Expires=Wed,11Jan201716:43:53GMT

Transfer-Encoding:chunked

Whenwesetcookies,wewritethentotheHTTPresponsewhichwesendtotheclientandthebrowserreadstheCookieinformationandstorestheminthememoryorthefilesystemdependingontheExpiresfieldoftheresponse.

Fromthegodocumentation:

typeCookiestruct{

Namestring

Valuestring

Pathstring//optional

Domainstring//optional

Expirestime.Time//optional

RawExpiresstring//forreadingcookiesonly

//MaxAge=0meansno'Max-Age'attributespecified.

//MaxAge<0meansdeletecookienow,equivalently'Max-Age:0'

//MaxAge>0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]string//Rawtextofunparsedattribute-valuepairs

}

InputValidation

Formhandling

109

Page 110: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thebasicaspectofwebapplicationsisthatnodatacanbetrusted,eveniftheuserisn'tmaliciousherself,therearemanywaystotrickthebrowserintosendingHTTPrequestsandfoolingthewebservertorespondtowhatseemslikealegitimaterequest.Hencewehavetoverifyeverythingthatcomesfromtheuser.

Onemightargueherethatwedoallsortsofvalidationusingjavascript,buttherearewaystoevadeJSvalidations,thesimplestwayistodisableJSandmoresophisticatedwaysaretomanipulatetheHTTPrequestbeforethebrowsersendsit,itisliterallytrivialwhenweusejustthewebdevelopertoolsthatthesedaysbrowsersprovide.

ifformToken==cookie.Valueandtitle!=nilandcontent!=nil

Thetitleandcontentofthetaskismandatory,henceweaddedthenotnilpart.

Wedoinputvalidationwhenwedon'twantjunkdatatogointoourdatabase,supposetheuserhitthesubmitbuttontwice,orsomeotherscenario.Butwealsohavetoconsiderthecasewheretheuserwantstorunsomescriptonourwebsite,whichisdangerous,soweusethetemplate.HTMLEscapeStringmethodtoescapewhatmightruninmemoryofthecurrentbrowsersession.Eventhedatawhichcomesfromyourdropdownlistshouldbevalidated.

EverythinginawebformissentviaaRequestaswesawintheaboveexample,weuseadropdownlistwhenwehaveareexpectingaparticularsetofinputsbutforsomeonewhoknowswhatfirefoxdevtoolsare,caneasilymodifyanythingintherequest,forexamplewehavethepriorityasdropdownlistwemightthinkthatsincewehaveonlythreeentriesinthedropdownlist,shouldwekeepacheckinourviewhandlertonotacceptanythingbutthethreevalueswhicharepresentinourtemplate.Weoughttokeepachecklikebelow:

priorityList:=[]int{1,2,3}

for_,priority:=rangepriorityList{

iftaskPriority!=priority{

log.Println("incorrectprioritysent")

//mightwanttologassecurityincident

}

}

Thisisthepriorityfieldofourrequest

Content-Disposition:form-data;name="priority"

3

Formhandling

110

Page 111: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Allamalicioususerhastodoischangethisvalueandresendtherequest,theycanliterallyinsertanyvaluehere,justthinkwhatiftheysendrm-fr*.*andaccidentallyenoughthiscommandisexecutedonourserver.Thisalsobringsinanotheraspectofsecurity,neverrunyourmachineinrootmode,alwayskeeptherootmodeforadmintasksanduseanonrootmode.Evenifthatisn'tthecase,alessdangerousexamplewillbesendingahugenumberwiththerequest,assumingthatwehaveusedintegerasourvariable,theprogrammightcrashifithastohandleanumberbeyonditsstoragecapacity.Thismightbetermedasadenialofserviceattack.

Formhandling

111

Page 112: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

UploadingfilesUploadingfilesisthenextstepinformprocessing,incaseoffiles,wesendtheentirefiledataintheHTTPheader,sowehavetosettheformencodingtoenctype="multipart/form-data".Thiswillinformourserverthatwearegoingtogetafilefromtheformalongwiththerestofthefields,ifany.

Thismeanswecangeteithereitherfile(s)anddataorjustfile(s)orjustdataandnofile(s).

AtthefirstlineofourHTTPhandler,wehavetowritethisline,ifthislineisnotpresentinthefirstlinethenitgivesunexpectedresults

file,handler,err:=r.FormFile("uploadfile")

ifhandler!=nil{

r.ParseMultipartForm(32<<20)//definedmaximumsizeoffile

deferfile.Close()

f,err:=os.OpenFile("./files/"+handler.Filename,os.O_WRONLY|os.O_CR

EATE,0666)

iferr!=nil{

log.Println(err)

return

}

deferf.Close()

io.Copy(f,file)

filelink:="<br><ahref=./files/"+handler.Filename+">"+handler.File

name+"</a>"

content=content+filelink

}

Wefirstprovidethemaximumsizeofthefilewhichis32^20,whichisgiganticforourwebapp,noteveryonehastheInternetinfrastructuretouploadthatbigafile,butwewanttobeflexible.

Webasicallygetafilefromtheformrequest,intheformhandlerweopenanotherfilewiththesame/differentnameandthenreadthefileformtherequestandwriteitontheserver.Weneedtohandlethescenewherewenamethefiledifferentlysowe'dneedtostoretheoldfilename->newfilenamerelationsomewhere,itcanbeadatabasetable.

Thefilenameshouldbescrubbed,sincetheusercangiveanymaliciousnametodamageourapplication.

Wenowwanttorandomizethefilenameofthefileswhichtheusersupload.InyourAddTaskFuncaddthefollowinglines

UploadingFiles

112

Page 113: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ifhandler!=nil{

r.ParseMultipartForm(32<<20)//definedmaximumsizeoffile

deferfile.Close()

randomFileName:=md5.New()

io.WriteString(randomFileName,strconv.FormatInt(time.Now().Unix(),10))

io.WriteString(randomFileName,handler.Filename)

token:=fmt.Sprintf("%x",randomFileName.Sum(nil))

f,err:=os.OpenFile("./files/"+token,os.O_WRONLY|os.O_CREATE,0666)

iferr!=nil{

log.Println(err)

return

}

deferf.Close()

io.Copy(f,file)

filelink:="<br><ahref=/files/"+token+">"+handler.Filename+"</a

>"

content=content+filelink

fileTruth:=db.AddFile(handler.Filename,token)

iffileTruth!=nil{

message="Erroraddingfilenameindb"

log.Println("erroraddingtasktodb")

}

}

file~/Tasks/db/db.go

//AddFileisusedtoaddthemd5ofafilenamewhichisuploadedtoourapplicat

ion

//thiswillenableustorandomizetheURLwithoutworryingaboutthefilenames

funcAddFile(fileName,tokenstring)error{

SQL,err:=database.Prepare("insertintofilesvalues(?,?)")

iferr!=nil{

log.Println(err)

}

tx,err:=database.Begin()

iferr!=nil{

log.Println(err)

}

_,err=tx.Stmt(SQL).Exec(fileName,token)

iferr!=nil{

log.Println(err)

tx.Rollback()

}else{

log.Println(tx.Commit())

}

returnerr

}

UploadingFiles

113

Page 114: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

tablestructure

CREATETABLEfiles(namevarchar(1000)notnull,autoNamevarchar(255)notnull);

Theseblockofcodedothefollowingthings:

1. Createaversionofnameforeachuploadedfile2. Insertitindatabase3. Referencethefileas/files/<randomName>4. Fileisnowreferencedbyournameratherthantheusersuppliedname

Thenextparttodoisregisteringthe/files/handler.

file:~/Tasks/views/views.go

//UploadedFileHandlerisusedtohandletheuploadedfilerelatedrequests

funcUploadedFileHandler(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

log.Println("intothehandler")

token:=r.URL.Path[len("/files/"):]

//file,err:=db.GetFileName(token)

//iferr!=nil{

log.Println("servingfile./files/"+token)

http.ServeFile(w,r,"./files/"+token)

//}

}

}

UploadingFiles

114

Page 115: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Templatespackage:text/template

Inthefirstchapterwehadacursoryglanceovertheconceptoftemplates.Thischapterisdedicatedentirelytotemplates.Aswesaidpreviously,awebapplicationrespondstocertainURLsandgivesanhtmlpagetothebrowserwhichthebrowsertheninterpretsandshowstotheenduser.Thishtmlpagewhichissenttothebrowseriswhatiscalledtemplatesinthebackendforwehaveatemplatewhichstoressomevariables,andinrealtimedataisprovidedintothetemplatewhichmakesitacompletehtmlpage.

Let'stakeapracticalexample.Supposewearebuildingamicrobloggingsite.Wewouldstartwithcreatingthefrontendinhtml.OurmicrobloggingsitewillshowHiUserontherightcorner.

Inourstatichtmlwewritethis<p>HiUser</p>

Butifweservethispageonourwebserverit'llnotchangeanything,it'llshowHiUser,thenameoftheuserwon'tcomemagically,wehavetoputitintothepagesomehow,hereweuseavariablesoinGowe'dapproachthisbyusingavariablenamed{{.Name}}soourhtmlnowwillbe<p>Hi{{.Name}}</p>.The.ismandatory.

Now,thisisthelogicweapplytoallourhtmlpages,keepingsuch{{}}variableexpansionparametersandservingthevalueoftheparameterwhileexecutingthetemplate.Ifyouarewonderinghowwe'ddothat,thisisthesyntax

homeTemplate.Execute(w,context)

//Contextisthestructpassedtotemplates

typeContextstruct{

Tasks[]Task

Namestring

Searchstring

Messagestring

}

Thesearethethreepartsofusingtemplates,firstyouneedtocreatetypeslikewehavecreatedtheContexttype,thenweneedtoreadthetemplate,thenweneedtousethecomponentsofthattypeinourtemplatefile.Sowhatremainsnowispassinganobjectofthattypeduringtemplateexecution.

Everytemplaterequiresthecontextobjectbecausethatiswhatdefinesthedatatobepopulatedinthetemplate.

Templates

115

Page 116: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Readingtemplate:

templates,err=template.Must(template.ParseFiles(allFiles...))

Note:template.Must

Mustisahelperthatwrapsacalltoafunctionreturning(*Template,error)andpanicsiftheerrorisnon-nilWhereallFilesispopulatedasbelow:

varallFiles[]string

templatesDir:="./public/templates/"

files,err:=ioutil.ReadDir(templatesDir)

iferr!=nil{

fmt.Println("Errorreadingtemplatedir")

}

for_,file:=rangefiles{

filename:=file.Name()

ifstrings.HasSuffix(filename,".html"){

allFiles=append(allFiles,templatesDir+filename)

}

}

ForthesakeofdemonstrationofhowtoparsemultiplefileswehaveusedtheParseFilesmethodtoparseallthe.htmlfiles,youcanusetheParseGlobmethodwhichisavailableinthestandardlibrary.

template.Must(template.ParseGlob(templatesDir+"*.html"))

ThedefinitionofParseGlobis:funcParseGlob(patternstring)(*Template,error)

WehavetospecifythePatternfortheParseGlobfunction,butwehavepassedthepathandthepatternbecausejustpassingthepatternisuseless,weneedthepathwherethepatternwillbeappliedtofindthelistofallfilesmeetingthecriteria.

Note:

1. ...operator:allFilesisastringsliceandallFiles...passesthefunctionaparameterasastring.

2. ParseFilesperformance:

Thereisonepointtonotehereaboutperformanceinparsingfiles,typicallyatemplatefilewon'tchangeuntilthereissomemajorchangetothecodebasesoweshouldonlyparsethefilesonce,ratherthankeepthiscodeineachviewhandleranddoinga

Templates

116

Page 117: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

template.ParseFiles("home.html")

template.Execute(w,context)

Thisblockofcodewillunnecessarilyreadthehtmlpageeachtimewhileservingtheresponseofarequest,whichmeansiftenpeopleareusingourbloggingsitethenforeachpagetheyvisitthecodewillreadthehtmlpage,butthereisnoneedtodothingsthisway,wecanreadthehtmlfilesonceatthestartandthenusetheLookupmethodofthetemplateclass,

homeTemplate=templates.Lookup("home.html")

homeTemplate.Execute(w,context)

SubtemplatingWelearnthowtopassdatatotemplatesanddisplayitinthehtmlpage,itsohappensthatalotofcodeisusedinalltemplatessupposethenavigationbarortheheader,thenweneednotwritethesamechunkeverywhere,wecancreateatemplatetostorethat,andusesubtemplating{{template"_head.html".}}

Here,wehaveidentifiedachunkofcodewhichwewanttoreplicateandputitin_head.html.Thenweputtheabovestatementineachtemplatefilewherewewishtohaveourheader.Thiswaytemplatesbecomealotsmalleranddon'tcontainreplicatedcodeeverywhere.Donotethatthe.beforethefirst}isintentionalanditmeansthatallthevariableswhichwerepassedtothecurrenttemplatearepassedtothesubtemplate.

Thesubtemplateswhichwecreatedependsonourrequirement,butthebasicpointbehinditisthatifwearegoingtorepeatablockofHTMLcodethenweshouldformitasatemplate.

NoteUsingSubTemplates

Themainpointtonoteoverhereisthatwhenwearegoingtouseourtemplatesorsubtemplates,allthosehtmlfilesneedtobeparsed.Thebasicpointintemplatingisthatwehaveavariablewhichstoresalltemplatesevenifwearen'tgoingtorefertothatdirectlyinourcodeusingtheLookupmethodonthetemplatevariable.Thelookupmethodtakesthenameofthetemplate.Whenthe{{template_head.html.}}isevaluated,itgoestoourtemplatevariableandtriestofindoutthetemplateparsedwiththeexactname,ifitisnotpresentthenitdoesn'tcomplainbydefault,weshoulduseMustmethodifwewantittocomplain.

Templates

117

Page 118: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Examplefileviews/views.go

packageviews

import(

"io/ioutil"

"net/http"

"os"

"strconv"

"strings"

"text/template"

)

var(

homeTemplate*template.Template

deletedTemplate*template.Template

completedTemplate*template.Template

loginTemplate*template.Template

editTemplate*template.Template

searchTemplate*template.Template

templates*template.Template

messagestring

//messagewillstorethemessagetobeshownasnotification

errerror

)

//PopulateTemplatesisusedtoparsealltemplatespresentin

//thetemplatesfolder

funcPopulateTemplates(){

varallFiles[]string

templatesDir:="./public/templates/"

files,err:=ioutil.ReadDir(templatesDir)

iferr!=nil{

fmt.Println("Errorreadingtemplatedir")

}

for_,file:=rangefiles{

filename:=file.Name()

ifstrings.HasSuffix(filename,".html"){

allFiles=append(allFiles,templatesDir+filename)

}

}

iferr!=nil{

fmt.Println(err)

os.Exit(1)

}

templates,err=template.Must(template.ParseFiles(allFiles...))

//templates,err:=template.Must(template.ParseGlob(templatesDir+".html"

))

Templates

118

Page 119: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

iferr!=nil{

fmt.Println(err)

os.Exit(1)

}

homeTemplate=templates.Lookup("home.html")

deletedTemplate=templates.Lookup("deleted.html")

editTemplate=templates.Lookup("edit.html")

searchTemplate=templates.Lookup("search.html")

completedTemplate=templates.Lookup("completed.html")

loginTemplate=templates.Lookup("login.html")

}

//ShowAllTasksFuncisusedtohandlethe"/"URL

//TODOaddhttp404error

funcShowAllTasksFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

context:=db.GetTasks("pending")

//truewhenyouwantnondeletednotes

ifmessage!=""{

context.Message=message

}

homeTemplate.Execute(w,context)

message=""

}else{

message="Methodnotallowed"

http.Redirect(w,r,"/",http.StatusFound)

}

}

Loopingthrougharrays

<divclass="timeline">

{{if.Tasks}}

{{range.Tasks}}

<divclass="note">

<pclass="noteHeading">{{.Title}}</p>

<hr>

<pclass="noteContent">{{.Content}}</p>

</div>

{{end}}

{{else}}

<divclass="note">

<pclass="noteHeading">NoTaskshere</p>

<pclass="notefooter">Createnewtask<button>here</button></p>

</div>

{{end}}

</div>

Templates

119

Page 120: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

The{{if.Tasks}}blockchecksifthearrayisemptyornot,ifitisnotthenit'llgotothe{{.range.Tasks}}whichwillloopthroughthearray,thenthe{{.Title}}willaccessthetitleand{{.Content}}willaccesstheContentofthatparticularTaskinstanceandwe'llseeallthetasksasalist.

Templatevariables

Wehavethisscenario,wehavearangeofcategoriesinthenavigationdrawerandifwevisitthe/category/study,thenourcategorynameshouldbehighlightedinthenavigationdrawer.Wedothisbystoringthevalueofthe.Navigationfield-whichtellsifitisaEditpage/Trashpage/Categorypage

{{$nav:=.Navigation}}

{{range$index,$cat:=.Categories}}

<liclass="sidebar-item">

<ahref="/category/{{$cat.Name}}"{{ifeq$cat.Name$nav}}class="active"{{

end}}>

<spanclass="nav-item">{{$cat.Name}}</span><spanclass="badgepull-right

">{{$cat.Count}}</span></a>

</li>

{{end}}

Creatingvariables

{{$url:=""}}willcreateablankvariable,onehastonotthatallvariablesarepracticallystringsoncetheyarerendered.{{$url:=.Navigation}}willcreateanewvariableandinitializeitwiththevalueof.Navigation

Forunderstandingwhytemplatevariablesarerequired,weneedtogointotheaboveblockofcode,whenweareusingtherangeoperator,weareparsingthearrayandtherangeblockgetstheelementsoftheblockbydefault.

MyContexttypeis

typeContextstruct{

Tasks[]Task

Navigationstring

Searchstring

Messagestring

CSRFTokenstring

Categories[]CategoryCount

Refererstring

}

Templates

120

Page 121: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Hencewhenwedoa{{range.Categories}}wewillbeaccessingeachelementas{{.}}perloop.Ifweuseanyothervalidvariablehere,likethe.Navigation,thentheblocktriestofindthe.Navigationinside.Categories,whichobviouslyisn'tpresent.

Nowweneedtomakethepageawareofwhichcategoryitisshowing,shouldtheusergotothe/categories/page.

ThelogicbehindmakingthatpagecategoryawareisthatwecreateaCSSclasstomarkthatparticularcategoryasactive,butforthat,we'dneedtoaccesstheCategorynameandNavigationwithintherange.Categoriesblock,thuswecreatetwovariables,onetostorethecategorynamefromthe.Navigationvariableandusetheifstatementlike

{{ifeq$cat$nav}}class="active"{{end}}

Thiswillmarkonlythatparticularcategoryasactiveandnotallofthem.

Intemplatinglogictheoperatorisfirstandthenthetwooperands.

eq:equal,le:lessthanequal,ge:greaterthanequal

Youcanalsouseifelseclauselikebelow:

{{$url:=""}}

<divclass="navbar-header">

{{if.Search}}<aclass="navbar-brand">Resultsfor:{{.Search}}</a>{{else}}{{i

feq.Navigation"pending"}}

{{$url:=""}}{{elseifeq.Navigation"completed"}}{{$url:=""}}{{elseife

q.Navigation"deleted"}}

{{$url:=""}}{{elseifeq.Navigation"edit"}}{{$url:=""}}{{else}}{{$url:=

"/category"}}{{end}}

<pclass="navbar-brand"href="{{$url}}/{{.Navigation}}">

{{ifeq.Navigation"pending"}}Pending{{elseifeq.Navigation"completed"}

}Completed{{elseifeq.Navigation"deleted"}}Deleted

{{elseifeq.Navigation"edit"}}Edit{{else}}{{.Navigation}}{{end}}{{en

d}}

</p>

Herewehadsomecomplicatedstuff,ifourpageisasearchone,wehadtoshowResultsfor:<query>,pending,deleted,edit,completedforrespectiveand/category/ifweareinthecategory.SowedefinedanemptyURLandassignedtheURLvaluesaccordingtothecomplicatedifelsestructure.

Homework

Templates

121

Page 122: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

1. Takethehtmlpagesfromhttp://github.com/thewhitetulip/omninoteswebandmodifythemtosuitourpurposesWewouldneedtocreateonetemplateeachfortheoneswementionedintheabovevariabledeclaration,usetemplatingasfaraspossibleandlatercheckyourresultswithhttp://github.com/thewhitetulip/Tasks,pleasedotheexerciseonyourownfirstandthenonlychecktheTasksrepository.

2. Implementasearchinterface.Takeaqueryasinput,searchtasksforthatqueryandreturnanhtmlpagewiththequeryhighlightedintheresultingpage.

Templates

122

Page 123: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

AuthenticationAuthenticationisusedtoverifyiftheusershaveaccesstothatparticularpartofyourwebapplication.Forunderstandinghowtoimplementauthenticationweneedtounderstandwhathappensbehindthescenesofabrowser.Supposewerunabankwebapplication.Wewantonlyourlegitimateuserstoaccessourwebapplication.Wesetupaloginpageandprovideouruserswiththeirusernameandpasswordwhichtheycanusetovalidatetheirclaimtoourwebapp.

Whenwesubmittheloginform,thebrowsertakesourusername,passwordandsendsaPOSTrequesttothewebserver,whichagainrespondswithaHTTPredirectresponseandwearereturnedtoourbankdashboard.

TheHTTPprotocolisstateless,whichmeanseveryrequestisunique.Thereisnowayforidentifyingautomaticallyifarequestisrelatedtoanotherrequest.Thisbringsabouttheproblemofauthentication,howthencanwevalidateiftheusershaveaccesstoourwebapp?

WecansendtheusernamealongwitheachHTTPrequest,eitherintheURLviaaGETrequestorinthePOSTrequest.Butthisisinefficientsinceforeachrequest,thewebserverwouldneedtohitthedatabasetovalidatetheusername,alsothiswouldmeanweaksecuritysinceifIknowyourusername,Icanimpersonateyouprettyeasilyandthewebserverishelplesstoidentifythisimpersonation.

TosolvethisproblemsSessionswereinvented,sessionsneedtousecookiesonthebrowsertofunction.ThebasicideaisthattheservergeneratesasessionIDandstoresitinacookie.Withsubsequentrequests,thebrowserwillsendthesessionIDalongwiththerequest,thewebserverwillthencometoknowfromthatsessionIDiftherequestisafakeoneornot.Alsowegettoknowwhotheuserisfromthat.

Cookies

Cookies,aswesawinapreviouschaptercanbeusedtostoreakey,valuepair.WeusedacookietostoretheCSRFtoken,thecookiehadthenameasCSRFandvalueasthetoken.

Pleasedon'tconfusesessionswithcookies,becausesessionsaren'takey,valuepair.Sessionsareawayofworkingwithcookiesontheserverside.ThereisagapoftheentireInternetbetweensessionsandcookies.

UserAuthentication

123

Page 124: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Cookiesarestoredinourbrowsers,forsecurityreasonsweneedtoenablethe"isHTTPOnly"fieldofourcookies,soonlyourwebapplicationcanreadthecookie.Otherwiseanyonejavascriptapplicationcaneasilyreadourcookiedefeatingitspurpose,wemightaswellnotkeepanauthenticationmechanismforourwebapp.

FromthegodocumentationtypeCookiestruct{NamestringValuestring

Pathstring//optional

Domainstring//optional

Expirestime.Time//optional

RawExpiresstring//forreadingcookiesonly

//MaxAge=0meansno'Max-Age'attributespecified.

//MaxAge<0meansdeletecookienow,equivalently'Max-Age:0'

//MaxAge>0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]string//Rawtextofunparsedattribute-valuepairs

}

Thedomainofourcookieenablesarestrictedaccesstoourcookie.Avisitorgoestoourfictionalbankwebsite,sbank.comandentersausernameandpassword,acookieisstoredinthebrowserwhichonlythesbank.comdomaincanaccesssincewearesecurityawareandwehavesettheHttpOnlyfieldtotruewhilesettingthecookie.Thismeanssomemaliciouswebsitewhichissetupbyanattackertointentionallytargetourbankisn'tabletoaccessthecookieusingjavascript.

Onehastorememberthatcookieisnothingbutafilestoredinauser'sbrowser,ifcanbeaccessedoverHTTPbyourwebserver,aclientbrowserdoesallowaccesstoitthroughbrowsersettingsorcustomjavascript.Thebrowser,afterallisaplatform,andwehaveAPIstothatplatform.

Sessions

Asessionisaseriesofactionsperformedbetweenyouandthewebappyouareacting,enabledbythebrowserandtheInternetyouareusing.Whilegeneratinganewsession,weneedtocheckifasessionsisalreadyactive,ifsowereturnthesamesessionIDratherthancreateanewone,ifnot,wegenerateanewsessionID.SessionIDsneedtobesufficientlyrandom.Ofcoursewecan'tgeneratesomethingtotallyrandom,butwehavetoensuretogeneratesomethingthatnobodyelsecanreplicate,unlesstheyhaveaccesstoourprivatekeywhichweusetogenerateourrandomnumber.

UserAuthentication

124

Page 125: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Sessionhandlingusinggorilla/sessions

Tillnowweneverusedanythirdpartylibraryoraframeworkinthisbook,thisisforthefirsttimethatwearedoingso,asperthearrogantpeopleonHNwebetteruselibrariesforhandlingsessions,sincesecurityisthe#1aspectofanywebapplication,untilthetimeweareaspecialistinwebdevelopmentandcanwriteourownsessionmoduleitiswiserandsafertousingpre-builtpackages

Path:~/Tasks/sessions/sessions.go

packagesessions

import(

"net/http"

"github.com/gorilla/sessions"

)

//Storethecookiestorewhichisgoingtostoresessiondatainthecookie

varStore=sessions.NewCookieStore([]byte("secret-password"))

//IsLoggedInwillcheckiftheuserhasanactivesessionandreturnTrue

funcIsLoggedIn(r*http.Request)bool{

session,_:=Store.Get(r,"session")

ifsession.Values["loggedin"]=="true"{

returntrue

}

returnfalse

}

Thisisthesessionspackagewhichwewilluseinourapplication.

WecreateaCookieStorewhichstoresthesessionsinformationunderthe"sessions"inthebrowser.WegetthesessionIDstoredunderthesessioncookieandstoreitthesessionvariable.Whenitcomestousingthisfunction,wehavetheAddCommentFuncviewbelowwhichisgoingtohandlethecommentingfeatureofourapplication,it'llfirstcheckiftheuserhasanactivesessionandifso,it'llhandlethePOSTrequesttoaddacomment,ifnot,it'llredirecttheusertotheloginpage.

Path:~/Tasks/Views/addViews.go

UserAuthentication

125

Page 126: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//AddCommentFuncwillbeused

funcAddCommentFunc(whttp.ResponseWriter,r*http.Request){

ifsessions.IsLoggedIn(r){

ifr.Method=="POST"{

r.ParseForm()

text:=r.Form.Get("commentText")

id:=r.Form.Get("taskID")

idInt,err:=strconv.Atoi(id)

if(err!=nil)||(text==""){

log.Println("unabletoconvertintointeger")

message="Erroraddingcomment"

}else{

err=db.AddComments(idInt,text)

iferr!=nil{

log.Println("unabletoinsertintodb")

message="Commentnotadded"

}else{

message="Commentadded"

}

}

http.Redirect(w,r,"/",http.StatusFound)

}

}else{

http.Redirect(w,r,"/login",302)

}

}

Thebelowfilecontainsthecodetologinandlogoutofourapplication,webasicallyaregoingtosetthe"loggedin"propertyofourcookiestore.

Path:~/Tasks/Views/sessionViews.go

UserAuthentication

126

Page 127: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packageviews

import(

"net/http"

"github.com/thewhitetulip/Tasks/sessions"

)

//LogoutFuncImplementsthelogoutfunctionality.

//WIlldeletethesessioninformationfromthecookiestore

funcLogoutFunc(whttp.ResponseWriter,r*http.Request){

session,err:=sessions.Store.Get(r,"session")

iferr==nil{//Ifthereisnoerror,thenremovesession

ifsession.Values["loggedin"]!="false"{

session.Values["loggedin"]="false"

session.Save(r,w)

}

}

http.Redirect(w,r,"/login",302)

//redirecttologinirrespectiveoferrorornot

}

//LoginFuncimplementstheloginfunctionality,will

//addacookietothecookiestoreformanagingauthentication

funcLoginFunc(whttp.ResponseWriter,r*http.Request){

session,err:=sessions.Store.Get(r,"session")

iferr!=nil{

loginTemplate.Execute(w,nil)

//incaseoferrorduring

//fetchingsessioninfo,executelogintemplate

}else{

isLoggedIn:=session.Values["loggedin"]

ifisLoggedIn!="true"{

ifr.Method=="POST"{

ifr.FormValue("password")=="secret"

&&r.FormValue("username")=="user"{

session.Values["loggedin"]="true"

session.Save(r,w)

http.Redirect(w,r,"/",302)

return

}

}elseifr.Method=="GET"{

loginTemplate.Execute(w,nil)

}

}else{

http.Redirect(w,r,"/",302)

}

}

}

UserAuthentication

127

Page 128: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thereisabetterwayofhandlingsessionsusingmiddleware,we'llintroducethatconceptinthenextchapter.

Users

Signingusersup

Theaboveexamplejusthardcodestheusernameandpassword,ofcoursewe'dwantpeopletosignuptoourservice.Wecreateausertable.

CREATETABLEuser(

idintegerprimarykeyautoincrement,

usernamevarchar(100),

passwordvarchar(1000),

emailvarchar(100)

);

Forthesakeofsimplicity,it'llonlycontainID,username,passwordandemail.

Therearetwopartshere,firstonewhereweallowuserstosignup,andanotherpartwherewereplacethehardcodedusernameandpasswordinourloginlogic.

file:~/Tasks/main.go

http.HandleFunc("/signup/",views.SignUpFunc)

file:~/Tasks/views/sessionViews.go

UserAuthentication

128

Page 129: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//SignUpFuncwillenablenewuserstosignuptoourservice

funcSignUpFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="POST"{

r.ParseForm()

username:=r.Form.Get("username")

password:=r.Form.Get("password")

email:=r.Form.Get("email")

log.Println(username,password,email)

err:=db.CreateUser(username,password,email)

iferr!=nil{

http.Error(w,"Unabletosignuserup",http.StatusInternalServerError)

}else{

http.Redirect(w,r,"/login/",302)

}

}

}

file:~/Tasks/db/user.go

//CreateUserwillcreateanewuser,takeasinputtheparametersand

//insertitintodatabase

funcCreateUser(username,password,emailstring)error{

err:=taskQuery("insertintouser(username,password,email)values(?,?,?)",user

name,password,email)

returnerr

}

WesawTaskQueryinourchapteronDB,itisasimplewrapperarounddb.Exec().

Note:Inarealwebapp,you'dwanttoencryptthepasswordandnotstoreitinplaintext,thisisadummyappwhich'llneverseethelightofthedaysoIamkeepingitplaintext.

Login

file~/Tasks/views/sessionViews.go

UserAuthentication

129

Page 130: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//LoginFuncimplementstheloginfunctionality,willaddacookietothecookiestore

formanagingauthentication

funcLoginFunc(whttp.ResponseWriter,r*http.Request){

session,err:=sessions.Store.Get(r,"session")

iferr!=nil{

log.Println("erroridentifyingsession")

loginTemplate.Execute(w,nil)

return

}

switchr.Method{

case"GET":

loginTemplate.Execute(w,nil)

case"POST":

log.Print("InsidePOST")

r.ParseForm()

username:=r.Form.Get("username")

password:=r.Form.Get("password")

if(username!=""&&password!="")&&db.ValidUser(username,password){

session.Values["loggedin"]="true"

session.Values["username"]=username

session.Save(r,w)

log.Print("user",username,"isauthenticated")

http.Redirect(w,r,"/",302)

return

}

log.Print("Invaliduser"+username)

loginTemplate.Execute(w,nil)

}

}

file~/Tasks/db/user.go

UserAuthentication

130

Page 131: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//ValidUserwillcheckiftheuserexistsindbandifexistsiftheusernamepassword

//combinationisvalid

funcValidUser(username,passwordstring)bool{

varpasswordFromDBstring

userSQL:="selectpasswordfromuserwhereusername=?"

log.Print("validatinguser",username)

rows:=database.query(userSQL,username)

deferrows.Close()

ifrows.Next(){

err:=rows.Scan(&passwordFromDB)

iferr!=nil{

returnfalse

}

}

//Ifthepasswordmatches,returntrue

ifpassword==passwordFromDB{

returntrue

}

//bydefaultreturnfalse

returnfalse

}

Note:

Sinceweareusinggorilla/sessions,wejusthavetopluginthefunctionalitythatthepackageprovidesanddon'thavetobotherabouttheactualimplementationofsessionshandling,ifyouareinterestedthenbyallmeansgoaheadandcheckoutthesourcecodeofgorilla/sessions!

Wekeepresettingthepasswordasanexercise,formulateamechanismtoresettingthepassword,requiresustocreateausertableandstoresomeprofileinformation,eitheremail-IDfromwherewe'llsendasecuritycodeorbydoingsomethingelse!Brainstorm!

UserAuthentication

131

Page 132: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

FilesJSONandXMLaretwoofthemostcommonwaystotransmitdatabetweenwebapplications.We'lluseJSONforourconfigurationfile.

Forourwebapplicationwehaveasetofconfigurationvaluesliketheserverportwhereourapplicationwillrun.Supposeyouaredevelopingyourapplicationin$GOPATHandalsousingitsomewhereelse,thenyoucan'truntheminparallelbecausebothsourcesusethesameportnumber.Naturallywewantawaytoparameterizethatportnumber.Theparameterorconfigurationvaluelistmaycontainmorethingslikedatabaseconnectioninformation.Asofnowwewilluseaconfig.jsonfileandreadtheserverPortvariableandbindourserveronthatport.

Ourconfigurationfileusesafixedstructure,henceitissimpleenoughtoUnMarshalittoastructtype,wecanusesomeadvanceconceptstoaccomodateunstructuredJSONfiles,becausethatisthewholepointofJSON,wecanhavedatainanunstructuredformat.

NoSQLhasbeenfamouslately,theyarebasicallyJSONdocumentstores.Wehaveprojectslikeboltdbwhichstoredatainakeyvaluepair,ultimatelyinflatfilesorinmemory.

file:$GOPATH/src/github.com/thewhitetulip/Tasks/config/config.go

WorkingwithFiles

132

Page 133: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packageconfig

import(

"encoding/json"

"io/ioutil"

"log"

)

//Storesthemainconfigurationfortheapplication

//defineastructobjectcontaining

typeConfigurationstruct{

ServerPortstring

}

varerrerror

varconfigConfiguration

//ReadConfigwillreadtheconfig.jsonfiletoreadtheparameters

//whichwillbepassedintheconfigobject

funcReadConfig(fileNamestring)Configuration{

configFile,err:=ioutil.ReadFile(fileName)

iferr!=nil{

log.Fatal("Unabletoreadlogfile")

}

//log.Print(configFile)

err=json.Unmarshal(configFile,&config)

iferr!=nil{

log.Print(err)

}

returnconfig

}

file:$GOPATH/src/github.com/thewhitetulip/Tasks/config.json

{

"ServerPort":":8081"

}

file:$GOPATH/src/github.com/thewhitetulip/Tasks/main.go

values:=config.ReadConfig("config.json")

//valuesistheobjectnow,wecanusethe

//belowstatementtoaccesstheportname

values.ServerPort

WorkingwithFiles

133

Page 134: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Weusethejson.UnmarshaltoreadtheJSONfileintoourstructureobject.ThisisaverysimpleandbasicexampleofparsingJSONfiles,youcanhavenestedstructuresofmanylevelsinsidethemainconfigobject,butthatisthefeaturesofGo,solongasitcanberepresentedasaJSONdocumentyoucanusetheUnmarshalmethodtotranslatethefileintoanobjectwhichyoucanuseinyourprogram.

Homework

Altertheconfig.jsonfiletotakethenameofthesqlitedatabaseasaconfigurationparameter.ReadabouttheJSONlibraryingodoc

WorkingwithFiles

134

Page 135: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

RoutingTillnowweusedroutingdirectlyinsideofourhandlers.Foralargeapplicationthough,it'dbebettertohavearouterinplace.Wecaneitheruseathirdpartyonewithcountlessfeaturesorthestandardmux.

Asourapplicationmatures,routingplaysabigroleintoit.Weintentionallyavoidedroutingtillnowbecauseasawebdeveloper,wemustunderstandwhathappensinthebackgroundofourapplication.Webframeworksallowustobuildapplicationsquickly,butthedownsideofthemisthattheyprovideuswithaframeworkasthenamesuggests,whichmeansyouaretotallyrestrictedbytheAPIwhichtheframeworkwillprovide.Thusweneedtoknowhowtoimplementbarebonestuff,soinfuturewemightwanttomodifytheframeworkweneed,orrathercreateourownone.

Firstofallwe'dneedtoinstallthehttprouter,doagoget-ugithub.com/julienschmidt/httprouter

Fromthedocumentation

PackagehttprouterisatriebasedhighperformanceHTTPrequestrouter.

Routing

135

Page 136: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

packagemain

import(

"fmt"

"github.com/julienschmidt/httprouter"

"net/http"

"log"

)

funcIndex(whttp.ResponseWriter,r*http.Request,_httprouter.Params){

fmt.Fprint(w,"Welcome!\n")

}

funcHello(whttp.ResponseWriter,r*http.Request,pshttprouter.Params){

fmt.Fprintf(w,"hello,%s!\n",ps.ByName("name"))

}

funcmain(){

router:=httprouter.New()//createsanewrouter

router.GET("/",Index)//willdirecttheGET/requesttotheIndexfunction

router.GET("/hello/:name",Hello)//willredirecttheGET/nametoHello,stores

thenameoftheparameter

//intheavariableofhttprouter.Params

log.Fatal(http.ListenAndServe(":8080",router))

}

httprouterusesacustomHttp.HandleFuncmethodtoaccomodateparameterizedrouting.

Here,wecanrouteourrequestsdependingontheHTTPmethodthroughwhichitisused,andwecanhandleparameterizedroutingforfree.

Tohandlethatscenariowewereinitiallyusingther.URL.Pathvariableandthenextractingtheparameters,itisjustthesolutionoffindingthevariableparameteroftheURL,thereisawideareawherehttprouterisawesome,thereisnoneedtohandlethe/foreachrequests.

Inwebapplicationssometimeshavingaforwardslashisverycritical,theURLindexistotallydifferentfrom/indexandismarginallydifferentfrom/index/httproutertakescareofthetrailingslashes.TheGodefaultMUXrequiresyoutohandletheroutesinthedescendingorder,meaningthemostgenericURLthe"/"shouldbeatthebottomandtheleastgenericshouldbeatthetop,asitgoessequentiallyupanddownmatchingtheURLs,httprouterprovidesawidevarietyofadvantageswhenitcomestorouting.

Thisisbecauseourapplicationshouldseparateroutingfromthehandlerlogic,weweremixingitjusttogetafeelforhowtoprograminGo,buteventuallywhentheappgrows,itistiresomeandnonmaintainablefordoingtheifr.Method==POSTcheckineachhandler,

Routing

136

Page 137: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

ratherthanthatwecanhave3differenthandlersoneforwhenrequestcomesviaAJAX,onefornormalGETandonefornormalPOST.Thiswaywedonothaveonefunctionhandlercheckingthetypeofrequestandthenwritingthreeseparatelogicinsideonefunction.

Butthatdoesn'tmeanwehavetousehttprouter,ifinanapptherearen'tmuchsophisticatedroutingrequiredthenwecanusethedefaultMuxsinceitisgoodenough,butifwehavecomplicatedroutingthenhttprouteristhebest.

Homework

Readthehttprouterdocumentationandsourcecodetogetadeeperunderstandingofrouters,sinceroutersareanintegralpartofanywebapplication.Thenrewriteourapplicationusingthehttprouter.

Routing

137

Page 138: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

MiddlewaresMiddlewareisreallyanythingthatextendsyourwebappinamodularway.Mostcommonexamplesareprobablyparsingtherequestparameters/bodyandstoringtheminaneasily-accessibleformatsoyoudon'thavetodoitineverysinglehandler,orsessionhandlingaswementionedinthepreviouschapter.OtherexamplescouldbethrottlingorIPfiltering,whichwouldalsohappenbeforeyoustartbuildingyourresponse,orcompression,whichwouldhappenafteryou'vebuiltyourresponse.

//RequiresLoginisamiddlewarewhichwillbeusedforeach

//httpHandlertocheckifthereisanyactivesession

funcRequiresLogin(handlerfunc(whttp.ResponseWriter,r*http.Request))

func(whttp.ResponseWriter,r*http.Request){

returnfunc(whttp.ResponseWriter,r*http.Request){

if!sessions.IsLoggedIn(r){

http.Redirect(w,r,"/login/",302)

return

}

handler(w,r)

}

}

Theabovefunctioncountsasmiddleware-itdoesn'tknowanythingaboutyourappexcepthowyouhandlesessions.Ifyou'renotloggedin,itredirects,otherwiseitdoesn'tdoanythingandpassesalongtothenexthandler.Thatnexthandlermightbewhereyouactuallybuildyourresponse,oritcouldbeanothermiddlewarecomponentthatdoessomethingelsefirst.

Toknowsomeone'sloggedin,yes,youwanttocreateasessionidentifierandstorethatsomewhereontheserverside(inmemoryoradatabase)andalsosetitintheuser'scookies.YoursessionIDsshouldbesufficientlyrandomandlongthattheycouldn'tbeeasilyguessed.IthinkacommonwayofsatisfyingthatiscreatingaUUIDandthenbase64encodethat.Or,youcouldjustgenerateabunchofrandombytes.

Toknowwhichuserisloggedin,thesessionIDshouldbethekeythatmapstoauserID.So,you'dmakeamapofSessionID=>UserID,orsomethingsimilarinyourdatabase.

Then,beforeeveryrequest,you'd

1. Checkuser'scookiesforSessionID.Ifnone,userisnotloggedin.2. Checkyourstoreforuser'sSessionID.Ifit'snotfound,thenit'sinvalid-userisnot

loggedin.3. Ifyoufoundit,useittolookuptheuser'sID.Userisnowloggedin.

Middleware

138

Page 139: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

4. Nowyou'vegottheuserIDandcanuseitasafilterwhenqueryingyourDBifyouonlywanttoshowthatuser'stasks.

ExampleWithoutmiddleware:

//IsLoggedInwillcheckiftheuserhasanactivesessionandreturnTrue

funcIsLoggedIn(r*http.Request)bool{

session,_:=Store.Get(r,"session")

ifsession.Values["loggedin"]=="true"{

returntrue

}

returnfalse

}

//SearchTaskFuncisusedtohandlethe/search/url,handlesthesearchfunction

funcSearchTaskFunc(whttp.ResponseWriter,r*http.Request){

ifsessions.IsLoggedin(r){

ifr.Method=="POST"{

r.ParseForm()

query:=r.Form.Get("query")

context:=db.SearchTask(query)

categories:=db.GetCategories()

context.Categories=categories

searchTemplate.Execute(w,context)

}

}else{

http.Redirect(w,r,"/login/",302)

}

WithMiddleware:

http.HandleFunc("/",views.RequiresLogin(views.ShowAllTasksFunc))

//SearchTaskFuncisusedtohandlethe/search/url,

//handlesthesearchfunction

funcSearchTaskFunc(whttp.ResponseWriter,r*http.Request){

ifr.Method=="POST"{

r.ParseForm()

query:=r.Form.Get("query")

context:=db.SearchTask(query)

categories:=db.GetCategories()

context.Categories=categories

searchTemplate.Execute(w,context)

}

}

Middleware

139

Page 140: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

Thisway,wedonothavetorepeattheifsessions.IsLoggedin()blockineachofourviewwhichrequiresauthentication.Inthisexamplewehaveuseditforsessionhandling,butitcanbeusedforanypurposewhichrequiressomekindofprehandlingofanyview.

Middleware

140

Page 141: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

BuildinganAPIAPIstandsforApplicationProgrammingInterface,itisjustaninterfacetothewebapp.Whenweuseabrowsertoaccessawebapplication,weinteractinHTTPandgetbackHTMLpages,whichthebrowserwillrenderforus.Let'ssaywewanttointeractwithourwebapptogetsomedataoutofitusingahostprogramminglanguagelikeGoorPython.We'dhavetomaintaincookiesinPython,orwriteapythonmoduleasanextensionofabrowsertohandlethisscenario.

Thereisasimplewayoutofthis,weequipourwebapplicationitselftointeractwithanyhostlanguagewhichcantalkinHTTP.Thiswaydeveloperscaneasilygetaccesstooursystem,usingvalidcredentials,ofcourse.

Browser:

1. Wesendtheusername,passwordandgetacookiestoredonourmachine.2. WeusethetokeninthecookieuntilitisvalidtosendHTTPrequests.3. ThebrowserisresponsibleforrenderingtheHTMLpagessentbytheserver.

API:

1. Wesendtheusername,passwordandgetatoken.2. Wesendthistokenineachofourrequesttotheserver

TypicallywesendthetokeninacustomHTTPheadercalledtoken.

Whenweuseabrowser,theserverstoresourinformationasasession,whenwesenditarequest,itisawareofoursession.AwebapptypicallyusescookiestostorethesessionID,whichisusedtoidentifytheuser.Suchaserveriscalledastatefulserver.

WhenwewriteAPIs,theyarestatelessservers,theydonotstoresessionsinformationanywhereontheserver.Toit,eachrequestisunique.Whichiswhy,weneedtopassalongtheauthenticationtokenineachrequest.

Note:Don'tmessaroundwithtokens

Thereareappswhere"singlesignin"featureisavailable,theuserhastologinonlyonceandtheyareloggedinforever,thisisverydangerous.Becauseifamaliciouspersongetstheirhandsonthesecuritytoken,theycansendmaliciousrequestsfordatawhichlookgenuineandareimpossibletoclasifyasmalicious.Don'tdothis,alwayshavesomeexpirationtimeforsecuritytokens,dependsonyourapplicationreally,twohours,sixhours,butneverinfinitehours.

BuildinganAPI

141

Page 142: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

JWTJavascriptWebTokensisastandardforgeneratingtokens.Wewillusethejwt-golibrary.

Letsstartbydefiningourroutes

http.HandleFunc("/api/get-task/",views.GetTasksFuncAPI)

http.HandleFunc("/api/get-deleted-task/",views.GetDeletedTaskFuncAPI)

http.HandleFunc("/api/add-task/",views.AddTaskFuncAPI)

http.HandleFunc("/api/update-task/",views.UpdateTaskFuncAPI)

http.HandleFunc("/api/delete-task/",views.DeleteTaskFuncAPI)

http.HandleFunc("/api/get-token/",views.GetTokenHandler)

http.HandleFunc("/api/get-category/",views.GetCategoryFuncAPI)

http.HandleFunc("/api/add-category/",views.AddCategoryFuncAPI)

http.HandleFunc("/api/update-category/",views.UpdateCategoryFuncAPI)

http.HandleFunc("/api/delete-category/",views.DeleteCategoryFuncAPI)

file:main.go

WewillhavethesameURLsfortheAPI,butit'llstartwith/api/

OurlogicisthatwewillsendtheusernameandpasswordinaPOSTrequestto/api/get-token/thatwillreturnthetokenforus.

file:views/api.go

BuildinganAPI

142

Page 143: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

import"github.com/dgrijalva/jwt-go"

varmySigningKey=[]byte("secret")

//GetTokenHandlerwillgetatokenfortheusernameandpassword

funcGetTokenHandler(whttp.ResponseWriter,r*http.Request){

ifr.Method=="POST"{

//specifythealgorithmtogeneratetoken

token:=jwt.New(jwt.SigningMethodHS256)

r.ParseForm()

username:=r.Form.Get("username")

password:=r.Form.Get("password")

ifdb.ValidUser(username,password){

/*Settokenclaimsliketheusernamd

andtheexpirationtime*/

token.Claims["username"]=username

token.Claims["exp"]=time.Now().Add(time.Hour*2).Unix()

/*Signthetokenwithoursecretwhichisaglobal

variableinthesamefile*/

tokenString,_:=token.SignedString(mySigningKey)

/*Finally,writethetokentothebrowserwindow*/

w.Write([]byte(tokenString))

}else{

w.Write([]byte("Authenticationfailed"))

}

}

}

Thenextstepistovalidateatoken.

//ValidateTokenwillvalidatethetoken

funcValidateToken(myTokenstring)(bool,string){

token,err:=jwt.Parse(myToken,func(token*jwt.Token)(interface{},error){

return[]byte(mySigningKey),nil

})

if(err!=nil)||(!token.Valid){

returnfalse,""

}

returntoken.Valid,token.Claims["username"].(string)

}

BuildinganAPI

143

Page 144: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

We'llcalltheParsemethodonthetokenwhichwereceiveasaparameterinthefunctioncall.Thetoken.Validfieldisaboolenvariablewhichistrueifthetokenisvalidandfalseotherwise.

MakinganAPIcallMakinganAPIcallisanalogoustoournormalview.

BuildinganAPI

144

Page 145: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

//GetCategoryFuncAPIwillreturnthecategoriesfortheuser

//dependsontheIDthatweget,ifwegetall,thenreturnall

//categoriesoftheuser

funcGetCategoryFuncAPI(whttp.ResponseWriter,r*http.Request){

ifr.Method=="GET"{

varerrerror

varmessagestring

varstatustypes.Status

//getthecustomHTTPheadercalledToken

token:=r.Header["Token"][0]

w.Header().Set("Content-Type","application/json;charset=UTF-8")

IsTokenValid,username:=ValidateToken(token)

//Whenthetokenisnotvalidshowthe

//defaulterrorJSONdocument

if!IsTokenValid{

status=types.Status

{

StatusCode:http.StatusInternalServerError,

Message:message

}

w.WriteHeader(http.StatusInternalServerError)

//thefollowingstatementwillwritetheJSONdocumentto

//theHTTPResponseWriterobject.

err=json.NewEncoder(w).Encode(status)

iferr!=nil{

panic(err)

}

return

}

log.Println("tokenisvalid"+username+"isloggedin")

categories:=db.GetCategories(username)

w.Header().Set("Content-Type","application/json;charset=UTF-8")

w.WriteHeader(http.StatusOK)

err=json.NewEncoder(w).Encode(categories)

iferr!=nil{

panic(err)

}

}

}

DuringanAPIcall,wesenddatainJSONformat,forthat,weneedtosetourcontent-typeasapplication/json,bydoingthis,evenawebbrowserwilldetectthatitisgettingaJSONdocument.WhenweneedtowriteaJSONdocumenttotheresponsewriterobject,weuse

BuildinganAPI

145

Page 146: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

thejson.NewEncoder(w).Encode(categories)method,wherecategoriesisourJSONdocument.

FormattingaJSONdocumentThis,below,isourTasksstruct,whichwillbepopulatedasaJSONdocumentwhenwerunourserver.Asyoumightknow,wecan'tuseCapitalletterasthefirstletterinaJSONtitle,byconventiontheyshouldallbesmallletters.Gohasaspecialwayoflettingusdothat.Theexampleisbelow,whenwewritejson:"id",wearetellingGothatthenameofthisfieldinaJSONrenderingshouldbeidandnotId.Thereisanotherspecialsyntaxcalledomitempty,insomeJSOndocumentsyoumightwantsomefieldtonotbedisplayed.Itsohappensthattherearefieldswhichyouwouldwanttodisappearwhentheirvaluesaren'tpresent,theymaynotbeimportantorit'dbetooclunkytohavethemasNULLinallJSONdocuments.

typeTaskstruct{

Idint`json:"id"`

Titlestring`json:"title"`

Contentstring`json:"content"`

Createdstring`json:"created"`

Prioritystring`json:"priority"`

Categorystring`json:"category"`

Refererstring`json:"referer,omitempty"`

Comments[]Comment`json:"comments,omitempty"`

IsOverduebool`json:"isoverdue,omitempty"`

}

TestingAPIWe'lluseFirefoxandRestClientextensiontotestourAPI.RestClientallowsustosendvariousrequeststoourAPIserver,ifyouareonChrome,POSTmanisthebestalternative.

ForRestClienttosendFormdata,setacustomheaderName:Content-TypeValue:application/x-www-form-urlencoded

Otherwiseyou'llbesendingblankPOSTrequestsallthetime.Theserverneedstounderstandthecontenttypeofthedataitisgettingformtheclient.

Tosendtheactualformdata,example:wehavethreefields,username,passwordandname.Thenwewriteitinthebodysectionlikethis:

username=thewhitetulip&password=password&name=thewhitetulip

BuildinganAPI

146

Page 147: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

AlsosetacustomHTTPheaderbytheName:tokenValue:thetokenwhichyougetin/api/get-token/call

BuildinganAPI

147

Page 148: Table of Contents...Go basic knowledge Go foundation Control statements and functions struct Object-oriented interface Concurrency Summary General Go Programming Basics Web Programming

1.

Contributors

148