Jonathan.Cohlmeyer.Dev|

serverless-go-functions-on-netlify.html

November 27th, 2022

If you like the ease with which you can deploy websites to Netlify and have started to explore the fantastic world of Go, you may be excited to know that Netlify now supports serverless functions written in Go!

However, you probably found the Netlify documentation lacking and got frustrated trying to figure out how to write and deploy a serverless function in Go to Netlify. This was my experience, at least.

I then found an excellent blog that helped me work through these issues. However, this blog article was a bit outdated as some of the techniques used in the blog article do not work with the new Go modules. It also required manual copy and paste of your Go code into your Netlify site.

But there is now a better way!

So the first thing is to write a serverless function. You should put it in your GOPATH as normal. This should reflect the location where you plan to publish the code, such as Github, GitLab or Bitbucket.

mkddir ~/go/src/[your git host name such as github.com]/[your username or org name]/[your project name]

cd ~/go/src/[your git host name such as github.com]/[your username or org name]/[your project name]

Then initialize your module.

go mod init

Naming your module to match your online repository is common practice, and will help us deploy our code to Netlify.

Here is a minimum boilerplate for a Go function, lifted straight from the blog mentioned above. Paste it into your main.go file as a starting point.

package main

import (

    "github.com/aws/aws-lambda-go/events"

    "github.com/aws/aws-lambda-go/lambda"

)

func Handler(request events.APIGatewayProxyRequest) (*events.APIGatewayProxyResponse, error) {

    name := request.QueryStringParameters["name"]

    response := fmt.Sprintf("Hello %s!", name)

    return &events.APIGatewayProxyResponse{

        StatusCode: 200,

        Headers:    map[string]string{"Content-Type": "text/html; charset=UTF-8"},

        Body:       response,

    }, nil

}

func main() {

    // Initiate AWS Lambda handler

    lambda.Start(Handler)

}

The aws-lambda-go library is required to get any serverless function working on Netlify, as under the hood, Netlfiy used AWS serverless functions.

To install this dependency run:

go get ./...

Next, we want to test if our function actually works. Here is a starter test again pulled straight from the article I mentioned above. Put this into main_test.go

package main_test

import (

    "github.com/aws/aws-lambda-go/events"

    "github.com/stretchr/testify/assert"

    main "github.com/toddbirchard/netlify-serverless-tutorial"

    "log"

    "testing"

)

func TestHandler(t *testing.T) {

    tests := []struct {

        request events.APIGatewayProxyRequest

        expect  string

        err     error

    } {

        {

            // Test name has value

            request: events.APIGatewayProxyRequest{QueryStringParameters: map[string]string{"name": "Paul"}},

            expect:  "Hello Paul!",

            err:     nil,

        },

        {

            // Test name is null

            request: events.APIGatewayProxyRequest{},

            expect:  "Hello !",

            err:     nil,

        },

    }

    for i, test := range tests {

        response, err := main.Handler(test.request)

        assert.IsType(t, test.err, err)

        assert.Equal(t, test.expect, response.Body)

        log.Printf("Test %d: %s", i, response.Body)

    }

}

You should now be able to run your tests after you install the new dependencies:

go get ./...

go test ./...

Next, commit your code and push it up to your online repository.

After all, this is said and done, how on earth do you get this Go code working as a serverless function with your Netlify repository?

It mostly comes down to your netlify.toml and a makefile.

First, we will need to update our Netlify configuration file netlify. toml to use our make file for building. We also want to make sure you point to the directory where you want to store your functions. Please note you may wish to change your publish and functions folder depending on where your compiled assets are and where you want to keep your functions (the default is netlify/functions). You may also want to change to the Go version required.

[build]

  base = "/"

  command = "make build"

  publish = "dist"

  functions = "functions"

[build.environment]

  GO_VERSION = "1.19.1"

Next, the makefile. This file is used to issue several commands instead of jamming them all into the build command. Create a file named makefile at the root of your Netlify project.

Paste the following into your file as a start, modifying the variables marked by the square brackets to your use case. Also, you only need to create the functions folder if it does not already exist in your Netlify project.

build:
	npm run-script build
	mkdir -p functions
	GOBIN=${PWD}/functions go install [your git host name such as github.com]/[your username or org name]/[your project name]@[version number to install such as v0.0.1 or latest]

Now, if you have a private repository, you should add a line before you call go install to create a .netrc file that will get your credentials from your environment variables.

echo "machine [your git hostname] username ${GITUSERNAME} password ${GITTOKEN}" > ~/.netrc

Before you deploy, you will have to set several environment variables in Netlify.

GOOS=linux
GOARCH=amd64
GO111MODULE=on

In addition, if you have a private repository, you will have to set the credentials as environment variables for use in your .netrc file.

GIT_USERNAME=[your git username or token id]
GIT_TOKEN=[your git token/api key]

We set Linux and amd64 as the target for the build as this is the OS and architecture where the serverless functions will be run on AWS.

Next, you can commit and push your code, watch Netlify build, and place your function on AWS ready for you. You can watch the logs on the Netlify dashboard.

If you want to do the same with background functions, make sure to name your Go module with the suffix -background.

Background functions do not return anything to the browser, but you can view the logs on Netlify so fmt.Println and similar are your friends.