Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
Google Cloud Functions is an event-driven serverless compute platform. Cloud Functions allows you to write your code without worrying about provisioning resources or scaling to handle changing requirements.
There are two types of Cloud Functions:
This codelab will walk you through creating your own Cloud Function in Go.
In this codelab, you will publish and Cloud Function that when invoked via HTTP will display an image of the Go gopher, designed by Renee French.
gcloud
command line tool (download page). This comes pre-installed and configured when using Cloud Shell.While Google Cloud can be operated remotely from your laptop, in this codelab you will be using Google Cloud Shell, a command line environment running in the Cloud.
From the GCP Console click the Cloud Shell icon on the top right toolbar:
It should only take a few moments to provision and connect to the environment. When it is finished, you should see something like this:
This virtual machine is loaded with all the development tools you'll need. It offers a persistent 5GB home directory, and runs on the Google Cloud, greatly enhancing network performance and authentication. All of your work in this lab can be done with simply a browser.
Run the following command from Cloud Shell to make sure the Cloud Functions API is enabled. This will make sure we can deploy Cloud Functions later in the codelab.
gcloud services enable cloudfunctions.googleapis.com
curl
to download a zip with the code for this codelab:curl -LO https://github.com/GoogleCloudPlatform/golang-samples/archive/master.zip
unzip
to unpack the code. This unpacks a directory (golang-samples-master
), which contains sample Go code for cloud.google.com.unzip master.zip
cd golang-samples-master/functions/codelabs/gopher
The gopher
directory contains the following directories and files:
$ sudo apt-get install tree # Optional.
$ tree # Optional.
.
├── cmd
│ └── main.go # Binary to run the function locally.
├── go.mod # Go module definition.
├── gophercolor.png # The gopher!
├── gopher.go # Go file with the function.
└── gopher_test.go # Go test file.
HTTP Cloud Functions in Go are written as http.HandlerFunc
functions, which is an interface defined in the Go standard library. The function must:
http.HandlerFunc
type, meaning the function is of the form func(http.ResponseWriter, *http.Request)
. (See the Writing Web Applications tutorial for an in-depth guide to writing a full web application in Go.) For example, here is a "Hello, world" function:package gopher
import (
"fmt"
"net/http"
)
// HelloWorld prints "Hello, world."
func HelloWorld(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, world.")
}
You can open this file in Cloud Shell by opening the editor (click the pencil icon at the top right of Cloud Shell) then using the file tree on the left side of the editor to open the file, golang-samples-master/functions/codelabs/gopher/hello.go
.
Let's deploy this function as an HTTP Cloud Function! Make sure you cd golang-samples-master/functions/codelabs/gopher/
, then you can deploy it using the function name and gcloud functions deploy
. This may take a minute or two.
gcloud functions deploy HelloWorld \ --runtime go111 \ --trigger-http \ --allow-unauthenticated Deploying function (may take a while - up to 2 minutes)...done. availableMemoryMb: 256 entryPoint: Gopher httpsTrigger: url: https://region-my-project.cloudfunctions.net/HelloWorld ...
The --allow-unauthenticated
deploy option enables you to reach the function without authentication.
To test the HelloWorld
function, copy the httpsTrigger
URL that's displayed in the gcloud functions deploy
output. It will have a form like this:
https://<REGION>-<GOOGLE_CLOUD_PROJECT>.cloudfunctions.net/HelloWorld
Then run the following command:
curl https://<REGION>-<GOOGLE_CLOUD_PROJECT>.cloudfunctions.net/HelloWorld Hello, world.
Let's make the "Hello, world" function a bit more entertaining by printing an image of a Gopher for every request:
The following listing shows the code to make it happen. You can see this code in Cloud Shell at golang-samples-master/functions/codelabs/gopher/gopher.go
. After the code block, there are notes about each portion.
// Package gopher contains an HTTP function that shows a gopher.
package gopher
import (
"fmt"
"io"
"net/http"
"os"
)
// Gopher prints a gopher.
func Gopher(w http.ResponseWriter, r *http.Request) {
// Read the gopher image file.
// Uses directory "serverless_function_source_code" as defined in the Go
// Functions Framework Buildpack.
// See https://github.com/GoogleCloudPlatform/buildpacks/blob/56eaad4dfe6c7bd0ecc4a175de030d2cfab9ae1c/cmd/go/functions_framework/main.go#L38.
path := "serverless_function_source_code/gophercolor.png"
if _, err := os.Stat(path); os.IsNotExist(err) {
// Fall back to the current working directory if that file doesn't exist.
path = "gophercolor.png"
}
f, err := os.Open(path)
if err != nil {
http.Error(w, fmt.Sprintf("Error reading file: %v", err), http.StatusInternalServerError)
return
}
defer f.Close()
// Write the gopher image to the response writer.
if _, err := io.Copy(w, f); err != nil {
http.Error(w, fmt.Sprintf("Error writing response: %v", err), http.StatusInternalServerError)
}
w.Header().Add("Content-Type", "image/png")
}
import
block contains a list of other packages that this file depends on. These packages are referred to in the rest of the file using their name. For example, to use the ResponseWriter
type from the http
package, you write http.ResponseWriter
.Gopher
function declaration.gophercolor.png
file (see the sample code) using the os.Open
function.io.Copy
to copy the gopher image to w
, the http.ResponseWriter
argument. Everything written to w
will be sent in the HTTP response.Deploy this function as you did the "Hello, world" function from before, using gcloud functions deploy
and the name of the function, Gopher
:
gcloud functions deploy Gopher \ --runtime go111 \ --trigger-http \ --allow-unauthenticated
The --allow-unauthenticated
deploy option enables you to reach the function without authentication.
To test the function, visit the function's URL, which again is displayed in the gcloud functions deploy
command output in your browser. If everything is working correctly, you will see the gopher in your browser!
The next step is to add a test to make sure your function continues to work.
HTTP Cloud Functions in Go are tested using the testing
and httptest
packages from the standard library. There is no need to run an emulator or other simulation to test your function—just normal Go code.
Here is what a test looks like for the Gopher
function:
package gopher
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestGopher(t *testing.T) {
rr := httptest.NewRecorder()
req := httptest.NewRequest("GET", "/", nil)
Gopher(rr, req)
if rr.Result().StatusCode != http.StatusOK {
t.Errorf("Gopher StatusCode = %v, want %v", rr.Result().StatusCode, http.StatusOK)
}
}
func MyTest(t *testing.T)
. It must be exported and take one argument of type *testing.T
.httptest
package.To run these tests locally, cd
to the directory with the files you're testing then use the go test
command:
go test -v === RUN TestGopher --- PASS: TestGopher (0.00s) PASS ok github.com/GoogleCloudPlatform/golang-samples/functions/codelabs/gopher 0.037s
Next, you'll create a binary (package main
, in Go) so that you can run your function locally and try it in a browser.
You can run an HTTP function locally by creating an HTTP server and registering your function as a handler. (See the Writing Web Applications tutorial for an in-depth guide to writing a full web application in Go.)
You can write an HTTP server for your function in a subdirectory of your function. Following a Go convention, you name that directory cmd
and create a main.go
file inside it:
// The cmd command starts an HTTP server.
package main
import (
"fmt"
"log"
"net/http"
"github.com/GoogleCloudPlatform/golang-samples/functions/codelabs/gopher"
)
func main() {
http.HandleFunc("/", gopher.Gopher)
fmt.Println("Listening on localhost:8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}
package main
as the package. A main
package will be built as a binary that you can run.github.com/GoogleCloudPlatform/golang-samples/functions/codelabs/gopher
, based on the module
line of the go.mod
next to your function file. When you're writing your own functions, you can name the module whatever you prefer.func main()
is the entry point for the binary. It registers the gopher.Gopher
function as an HTTP handler then starts the server using http.ListenAndServe
.To build and run this binary locally, run the following commands:
GO111MODULES=on # Turn on Go modules. go build -o start ./cmd ./start Listening on localhost:8080
Because the function loads the gophercolor.png
image from the current working directory, you have to start your binary from the same directory as the gophercolor.png
file. The -o start
flag says to name the output binary start
. The ./cmd
says to build the binary located in the cmd
directory.
Now use the Cloud Shell Web Preview to test the server in your browser. Click the Web Preview button and then select port
8080
from the displayed menu. Cloud Shell opens the preview URL on its proxy service in a new browser window. The web preview restricts access over HTTPS to your user account only. If everything is working properly, you should see the Go Gopher!
Cloud Functions pricing is based on how often your function is invoked, including a free tier for functions that don't run often.
Once you're done testing your Cloud Functions, you can delete it using gcloud
:
gcloud functions delete Gopher gcloud functions delete HelloWorld
You can also delete the function from the Cloud Console UI.
We hope you enjoy using Cloud Functions in Go!