# HTTP Google Cloud Run Functions in Go - GSP602

## Overview

[Go](https://golang.org/) is an open source programming language that makes it easy to build simple, reliable, and efficient software. Go is already installed when using Cloud Shell.

[Cloud Run functions](https://cloud.google.com/functions/docs/concepts/overview) is a serverless execution environment for building and connecting cloud services. With Cloud Run functions, you write single-purpose functions that are attached to events emitted from your cloud infrastructure and services. Your function is triggered when an event being watched is fired. Your code executes in a fully managed environment in Cloud Run. There is no need to provision any infrastructure or worry about managing any servers.

You can write Cloud Run functions using supported programming languages. You can take your function and run it in any standard runtime environment for one of the supported languages, which makes both portability and local testing a breeze.

In this lab you use Go to create your own Cloud Run function that, when invoked via HTTP, displays an image of the [Go gopher](https://blog.golang.org/gopher), designed by Renee French.

### What you'll learn

* How to write an HTTP Cloud Run function in Go.
    
* How to test an HTTP Cloud Run function in Go.
    
* How to run a local Go HTTP server to try the function.
    

![The GO gopher mascot](https://cdn.qwiklabs.com/V4bvSBtlH7VBLdzAivGGdXT8Gnl%2FSoFdOANB79Ya1S4%3D align="left")

## Prerequisites

This lab assumes you are familiar with Go. Explanations are provided for the Go code, but may not explain everything needed for someone completely new to Go.

## Setup and requirements

### Before you click the Start Lab button

Read these instructions. Labs are timed and you cannot pause them. The timer, which starts when you click **Start Lab**, shows how long Google Cloud resources are made available to you.

This hands-on lab lets you do the lab activities in a real cloud environment, not in a simulation or demo environment. It does so by giving you new, temporary credentials you use to sign in and access Google Cloud for the duration of the lab.

To complete this lab, you need:

* Access to a standard internet browser (Chrome browser recommended).
    

**Note:** Use an Incognito (recommended) or private browser window to run this lab. This prevents conflicts between your personal account and the student account, which may cause extra charges incurred to your personal account.

* Time to complete the lab—remember, once you start, you cannot pause a lab.
    

**Note:** Use only the student account for this lab. If you use a different Google Cloud account, you may incur charges to that account.

### How to start your lab and sign in to the Google Cloud console

1. Click the **Start Lab** button. If you need to pay for the lab, a dialog opens for you to select your payment method. On the left is the Lab Details pane with the following:
    
    * The Open Google Cloud console button
        
    * Time remaining
        
    * The temporary credentials that you must use for this lab
        
    * Other information, if needed, to step through this lab
        
2. Click **Open Google Cloud console** (or right-click and select **Open Link in Incognito Window** if you are running the Chrome browser).
    
    The lab spins up resources, and then opens another tab that shows the Sign in page.
    
    ***Tip:*** Arrange the tabs in separate windows, side-by-side.
    
    **Note:** If you see the **Choose an account** dialog, click **Use Another Account**.
    
3. If necessary, copy the **Username** below and paste it into the **Sign in** dialog.
    
    ```apache
    student-04-afbea9349ccb@qwiklabs.net
    ```
    
    You can also find the Username in the Lab Details pane.
    
4. Click **Next**.
    
5. Copy the **Password** below and paste it into the **Welcome** dialog.
    
    ```apache
    aSn0tuqGObjS
    ```
    
    You can also find the Password in the Lab Details pane.
    
6. Click **Next**.
    
    **Important:** You must use the credentials the lab provides you. Do not use your Google Cloud account credentials.
    
    **Note:** Using your own Google Cloud account for this lab may incur extra charges.
    
7. Click through the subsequent pages:
    
    * Accept the terms and conditions.
        
    * Do not add recovery options or two-factor authentication (because this is a temporary account).
        
    * Do not sign up for free trials.
        

After a few moments, the Google Cloud console opens in this tab.

**Note:** To access Google Cloud products and services, click the **Navigation menu** or type the service or product name in the **Search** field.

![Navigation menu icon and Search field](https://cdn.qwiklabs.com/9Fk8NYFp3quE9mF%2FilWF6%2FlXY9OUBi3UWtb2Ne4uXNU%3D align="left")

### Activate Cloud Shell

Cloud Shell is a virtual machine that is loaded with development tools. It offers a persistent 5GB home directory and runs on the Google Cloud. Cloud Shell provides command-line access to your Google Cloud resources.

1. Click **Activate Cloud Shell** at the top of the Google Cloud console.
    
2. Click through the following windows:
    
    * Continue through the Cloud Shell information window.
        
    * Authorize Cloud Shell to use your credentials to make Google Cloud API calls.
        

When you are connected, you are already authenticated, and the project is set to your **Project\_ID**, `qwiklabs-gcp-04-90ca2870d60d`. The output contains a line that declares the **Project\_ID** for this session:

```sql
Your Cloud Platform project in this session is set to qwiklabs-gcp-04-90ca2870d60d
```

`gcloud` is the command-line tool for Google Cloud. It comes pre-installed on Cloud Shell and supports tab-completion.

3. (Optional) You can list the active account name with this command:
    

```apache
gcloud auth list
```

4. Click **Authorize**.
    

**Output:**

```apache
ACTIVE: *
ACCOUNT: student-04-afbea9349ccb@qwiklabs.net

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
```

5. (Optional) You can list the project ID with this command:
    

```apache
gcloud config list project
```

**Output:**

```apache
[core]
project = qwiklabs-gcp-04-90ca2870d60d
```

**Note:** For full documentation of `gcloud`, in Google Cloud, refer to [the gcloud CLI overview guide](https://cloud.google.com/sdk/gcloud).

### Set your region and zone

Certain Compute Engine resources live in regions and zones. A region is a specific geographical location where you can run your resources. Each region has one or more zones.

<aside><strong>Note</strong>: Learn more about regions and zones and see a complete list in<span> </span><a href="https://cloud.google.com/compute/docs/regions-zones/" target="_blank">Regions & Zones documentation</a>.</aside>

Run the following gcloud commands in Cloud Shell to set the default region and zone for your lab:

```apache
gcloud config set compute/zone "us-east1-d"
export ZONE=$(gcloud config get compute/zone)

gcloud config set compute/region "us-east1"
export REGION=$(gcloud config get compute/region)
```

### Ensure the Cloud Run functions API is enabled

* In Cloud Shell, run the following command to enable the Cloud Run functions API. This lets you deploy Cloud Run functions later in the lab.
    

```apache
gcloud services enable cloudfunctions.googleapis.com
```

### Download and setup the code

1. From the Cloud Shell terminal, use `curl` to download a zip with the code for this lab:
    

```sql
curl -LO https://github.com/GoogleCloudPlatform/golang-samples/archive/main.zip
```

2. Use `unzip` to unpack the code. This unpacks a directory (`golang-samples-main`), which contains sample Go code for [cloud.google.com](http://cloud.google.com/):
    

```apache
unzip main.zip
```

3. Change to the directory containing the code for this lab:
    

```apache
cd golang-samples-main/functions/codelabs/gopher
```

The `gopher` directory contains the following directories and files:

```apache
$ tree
.
├── 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.
```

## Task 1. Introduce HTTP Cloud Run functions in Go

HTTP Cloud Run functions in Go are written as [http.HandlerFunc](https://golang.org/pkg/net/http/#HandlerFunc) functions, which is an interface defined in the Go standard library. The function must:

* Be exported, meaning it can be used from another package, which is indicated by the name starting with an uppercase letter.
    
* Match the `http.HandlerFunc` type, meaning the function is of the form `func(http.ResponseWriter, *http.Request)`. (See the [Writing Web Applications](https://golang.org/doc/articles/wiki/) tutorial for an in-depth guide to writing a full web application in Go.)
    

For example, here is a "Hello, world" function:

```go
package gopher
import (
        "fmt"
        "net/http"
)
// HelloWorld prints "Hello, world."
func HelloWorld(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintln(w, "Hello, world.")
}
```

**Note:** You can open this file in Cloud Shell Editor (click **Open Editor**) then use the file tree on the left to open the file, `golang-samples-main/functions/codelabs/gopher/hello.go`.

### Deploy this function as an HTTP Cloud Run function

1. From the `functions/codelabs/gopher` directory you can deploy the function name with `gcloud functions deploy`:
    

```apache
gcloud functions deploy HelloWorld --gen2 --runtime go121 --trigger-http --region us-east1
```

2. Enter Y when asked to allow unauthenticated invocations of the new function.
    

This takes a minute or two.

**Output:**

```apache
Deploying function (may take a while - up to 2 minutes)...done.
availableMemoryMb: 256
entryPoint: HelloWorld
httpsTrigger:
  url: https://region-my-project.cloudfunctions.net/HelloWorld
...
```

Click *Check my progress* to verify the objective.

Create HelloWorld HTTP Cloud Run function

**Check my progress**

**Note:** Did you get an error during deployment? Check:

* Is the Cloud Run functions API enabled? If not, there will be an error with a link allowing you to enable it. Otherwise, you can enable it with the command `gcloud services enable cloudfunctions.googleapis.com`.
    
* Be sure your working directory (where you're running `gcloud` from) is the directory with the `.go` file in it. You can change directories using `cd golang-samples/functions/codelabs/gopher`.
    
* Is the function name correct? It should be `HelloWorld`, the name of the Go function you're trying to deploy.
    
* If you still get a permission denied error, wait a few minutes and try again.
    

3. Copy the `httpsTrigger` URL that's displayed in the output. It should look like this:
    

```apache
https://<REGION>-$GOOGLE_CLOUD_PROJECT.cloudfunctions.net/HelloWorld
```

4. To test the `HelloWorld` function, `curl` into the URL from the last output:
    

```apache
curl https://<REGION>-$GOOGLE_CLOUD_PROJECT.cloudfunctions.net/HelloWorld
```

**Output:**

```plaintext
Hello, world.
```

You've written and deployed a HTTPCloud Run function!

## Task 2. Write the Gopher HTTP Cloud Run function

Now make the "Hello, world" function a bit more entertaining by printing an image of a Gopher for every request.

![The Go gopher mascot](https://cdn.qwiklabs.com/V4bvSBtlH7VBLdzAivGGdXT8Gnl%2FSoFdOANB79Ya1S4%3D align="left")

The following block shows the code to make it happen. You can see this code in Cloud Shell at `golang-samples-master/functions/codelabs/gopher/gopher.go`.

```go
// 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.
        f, err := os.Open("gophercolor.png")
        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")
}
```

* The file starts with a package declaration and comment. All Go code is written inside a package, with a declaration like this at the top.
    
* The `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`.
    
* Next is the `Gopher` function declaration.
    
* The function starts by reading the `gophercolor.png` file (see the sample code) using the `os.Open` function.
    
* Then, it checks whether there was an error reading the file, which might occur if the file is corrupted or was accidentally left out of the upload.
    
* It uses `io.Copy` to copy the gopher image to `w`, the `http.ResponseWriter` argument. Everything written to `w` is sent in the HTTP response.
    
* If there was no error when writing the response, the function returns normally.
    

1. Deploy this function as you did the "Hello, world" function from before, using `gcloud functions deploy` and the name of the function, `Gopher`:
    

```apache
gcloud functions deploy Gopher --gen2 --runtime go121 --trigger-http --region us-east1
```

2. Enter Y when asked to allow unauthenticated invocations of the new function.
    
3. To test the function, visit the function's URL in the output from the last command. If successful, you see the gopher in your browser!
    

The next step is to add a test to make sure your function continues to work.

Click *Check my progress* to verify the objective.

Create the Gopher HTTP Cloud Run function

**Check my progress**

## Task 3. Write a test

HTTP Cloud Run functions in Go are tested using the [testing](https://golang.org/pkg/testing/) and [httptest](https://golang.org/pkg/net/http/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:

```go
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)
        }
}
```

* Go tests are written the same way as other Go files. They start with a package declaration and an import set.
    
* The test declaration is of the form `func MyTest(t *testing.T)`. It must be exported and take one argument of type `*testing.T`.
    
* The test creates test response and request values using the `httptest` package.
    
* It calls the Gopher function.
    
* After invoking the Gopher function, the test checks the HTTP response code to be sure there were no errors.
    

1. To run these tests locally, `cd` to the directory with the files you're testing:
    

```apache
cd ~/golang-samples-main/functions/codelabs/gopher
```

2. In the `golang-samples-main/functions/codelabs/gopher` directory, use the `go test` command:
    

```apache
go test -v
```

**Output:**

```apache
=== RUN   TestGopher
--- PASS: TestGopher (0.00s)
PASS
ok          github.com/GoogleCloudPlatform/golang-samples/functions/codelabs/gopher 0.037s
```

**Note:** Test not passing?

* Check the error message for anything helpful.
    
* Are you in the same directory as the `gopher.go` and `gopher_test.go` files (`golang-samples-main/functions/codelabs/gopher`)?
    

Next, you'll create a binary (`package main`, in Go) so that you can run your function locally and try it in a browser.

## Task 4. Run the function locally

To run an HTTP function locally, create an HTTP server and register your function as a handler. (See the [Writing Web Applications](https://golang.org/doc/articles/wiki/) 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:

```go
// 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))
}
```

* This file uses `package main` as the package. A `main` package will be built as a binary that you can run.
    
* This file imports `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.
    
* The `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`.
    

1. To build and run this binary locally, run the following commands:
    

```apache
GO121MODULES=on # Turn on Go modules.
go build -o start ./cmd
./start
```

**Output:**

```apache
Listening on localhost:8080
```

2. 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.
    
3. Now use the Cloud Shell Web Preview to test the server in your browser.
    

* Click the Web Preview button
    
    ![The web preview icon](https://cdn.qwiklabs.com/7b9oXblGsiFuNK7hmDZjFB%2B7Lrwdv5T64bbmo8X9FAo%3D align="left")
    
    .
    
* 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!

**Note:** Can't see the gopher?

* Are you in the same directory as the `gopher.go` and `gopher_test.go` files (`golang-samples-main/functions/codelabs/gopher`)?
    
* Has the server started? Be sure to build it with the `go build -o start ./cmd` command, then start it by running `./start`. It should print `Listening on localhost:8080`.
    
* Did you select the right port when opening the web preview? Be sure to use `8080`, the port the server is listening on.
    

## Task 5. Clean up

All resources you've used are deleted when you end this lab. When using your own environment, you should always remove extraneous resources to save on cost and to be a good cloud citizen.

1. Stop serving your URL with CTRL+C.
    
2. Once you're done testing your Cloud Run functions, you can delete it using `gcloud`:
    

```apache
gcloud functions delete Gopher --region us-east1
gcloud functions delete HelloWorld --region us-east1
```

You can also delete the function from the console.

---

## Solution of Lab

%[https://youtu.be/pPl-6kQ5wFA] 

```apache
curl -LO raw.githubusercontent.com/QUICK-GCP-LAB/2-Minutes-Labs-Solutions/refs/heads/main/HTTP%20Google%20Cloud%20Run%20Functions%20in%20Go/gsp602.sh
sudo chmod +x *.sh
./*.sh
```
