The official and recommended template for Go for OpenFaaS is golang-middleware.
It implements handler for HTTP requests using http.HandleFunc from Go's stdlib. It has support for Go modules, vendoring, unit testing, and adding static files.
Just like any other HTTP server written with the Go standard library, the incoming HTTP request is available via the http.Request object. The response is written to the http.ResponseWriter object. Any body passed in from the client should be closed to avoid any resource leaks.
If you have private code to include in your function from another repository, then the easiest way to do this is to use vendoring.
faas-cli new --lang golang-middleware secret-fn
Create a new function just like in the previous example, when you run go get, prefix it with GOPRIVATE, and make sure that any go commands that you run are performed inside the function's source code directory.
If you would like to include sub-modules, a certain replace statement is required in your go.mod file: replace handler/function => ./. This replace statement allows Go to see and use all sub-modules you create with-in your handler, for example
Create your sub-package i.e. handlers and run cd handlers ; go mod init
packagefunctionimport("fmt""handler/function/handlers")// Handle a serverless requestfuncHandle(req[]byte)string{handlers.Handle()returnfmt.Sprintf("Hello, Go. You said: %s",string(req))}
Now add the following replace statement to your go.mod
replace handler/function => ./
This can also be affected using
gomodedit-replacehandler/function=./
Now you can build with --build-arg GO111MODULE=on or with a build_arg map entry for the function in its stack.yml.
Example persistent database connection pool between function calls:
packagefunctionimport("database/sql""fmt""io""net/http""strings"_"github.com/go-sql-driver/mysql")// db pool shared between function callsvardb*sql.DBfuncinit(){varerrerrordb,err=sql.Open("mysql","user:password@/dbname")iferr!=nil{panic(err.Error())}err=db.Ping()iferr!=nil{panic(err.Error())}}funcHandle(whttp.ResponseWriter,r*http.Request){varquerystringctx:=r.Context()ifr.Body!=nil{deferr.Body.Close()// read request payloadbody,err:=io.ReadAll(r.Body)iferr!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)return}query=string(body)}// log to stdoutfmt.Printf("Executing query: %s",query)rows,err:=db.QueryContext(ctx,query)iferr!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)return}deferrows.Close()ids:=make([]string,0)forrows.Next(){ife:=ctx.Err();e!=nil{http.Error(w,e,http.StatusBadRequest)return}varidintiferr:=rows.Scan(&id);err!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)return}ids=append(ids,string(id))}iferr:=rows.Err();err!=nil{http.Error(w,err.Error(),http.StatusInternalServerError)return}result:=fmt.Sprintf("ids %s",strings.Join(ids,", "))// write resultw.WriteHeader(http.StatusOK)w.Write([]byte(result))}
packagefunctionimport("fmt""net/http")funcHandle(whttp.ResponseWriter,r*http.Request){// Parses RawQuery and returns the corresponding// values as a map[string][]string// for more info https://golang.org/pkg/net/url/#URL.Queryquery:=r.URL.Query()w.WriteHeader(http.StatusOK)w.Write([]byte(fmt.Sprintf("id: %s",query.Get("id"))))}