Functions Go Runtime

Functions are blocks of code that run on demand without the need to manage any infrastructure. Develop on your local machine, test your code from the command line (using doctl), then deploy to a production namespace or App Platform — no servers required.


Functions supports Go 1.17 (go:1.17) and Go 1.20 (go:1.20). Specify the desired runtime and version with the runtime key in your project.yml file, or by using the Runtime dropdown when creating a function through the control panel.

The Functions Go runtime passes two parameters to your handler function, and expects either no return value or a properly formatted response type.

A Go Hello World Function

Here is a Go function that responds with a greeting and some information about the function version:

package main

import (
	"context"
)

type Event struct {
	Name string `json:"name"`
}

type Response struct {
	Body string `json:"body"`
}

func Main(ctx context.Context, event Event) Response {
	if event.Name == "" {
		event.Name = "stranger"
	}
	version := ctx.Value("function_version").(string)
	return Response {
		Body: "Hello " + event.Name + "! This is function version " + version,
	}
}

The runtime expects a function called Main to act as the entry point or the handler. This handler function is the only function where the runtime passes in data and receive responses.

You can set a different function name as the handler using the main key in project.yml.

The Main function above takes two parameters: a ctx of the built-in type context.Context, and event with a custom Event type. It returns a response where the Body is a greeting to the user-provided Name (if any) in the event, and the function version provided in then context.

After adding this function to your namespace, you can call this function by pasting its URL into your browser and adding a name field in a query string at the end:

https://<your-function-url>?name=Sammy
Note

You can get the URL for your function from the control panel interface, or by running the following command on the command line:

doctl serverless function get <function-name> --url

Or use curl to send the input as form data in the body of the request:

curl -d 'name=Sammy' <your-function-url>

Either way, the function returns the response body:

Hello Sammy! This is function version 0.0.2

Parameters

The handler function is passed two parameters. The first represents the function’s execution context, and the second is the event, often representing an HTTP request.

Note
Information about function parameters that is not language-specific can be found in the Parameters and Responses reference documentation.

The first parameter, context, is data about the function’s execution environment, such as memory allocations and the time remaining before a timeout.

The second parameter, event, is the input event that initiated the function. When this is an HTTP event, it’s called a web event.

Both parameters are optional and you may ignore them if your function doesn’t require the information they provide. The parameter list for your handler function should look like one of the following:

  • (context.Context, yourEventType): Accesses both parameters, where yourEventType is any type that can be unmarshalled using the encoding/json package.
  • (context.Context): Accesses only the context.
  • (yourEventType): Accesses only the event, where yourEventType is any type that can be unmarshalled using the encoding/json package.
  • (): Accesses neither.

Event Parameter

The event parameter is unmarshalled from a JSON object. It is structured like the following example JSON:

{
  "http": {
    "headers": {
      "accept": "*/*",
      "accept-encoding": "gzip",
      "user-agent": "curl/7.85.0",
      "x-forwarded-for": "203.0.113.11",
      "x-forwarded-proto": "https",
      "x-request-id": "5df6f6b0d00b58217439c8376fcae23a"
    },
    "method": "POST",
    "path": ""
  },
  "shark": "hammerhead"
}

This example event has had a shark: hammerhead input passed to it. This has been parsed and added as a top-level key to the dictionary.

More details on the information contained in the event parameter is available under the Event Parameter section of the Parameters and Responses reference documentation.

Context Parameter

The context parameter is the context.Context type built into Go. The context has deadline and typed values that can be retrieved using the Value method.

See the official context.Context docs for more information on using this type.

The context parameter contains additional values. Here they are represented as keys of a JSON object with sample values. All of the context values are strings:

{
  "activation_id": "5f56b7e9fbd84b2f96b7e9fbd83b2f2e",
  "api_host": "https://faas-nyc1-2ef2e6cc.doserverless.co",
  "api_key": "",
  "function_name": "/fn-52ad03a2-8660-4f7c-55a5-81aa8bbe73b1/example",
  "function_version": "0.0.10",
  "namespace": "fn-52ad03a2-8660-4f7c-55a5-81aa8bbe73b1",
  "request_id": "452164dfeced0a7ad91ee675609024e7"
}

The context data doesn’t contain the deadline value. This is because Go contexts already have a concept of deadlines, so the runtime uses that. To get the deadline of the context, use the Deadline method:

deadline, _ := ctx.Deadline()

To retrieve values from the context parameter, use the Value method:

id := ctx.Value("activation_id").(string)

More details on the information contained in the context parameter is available under the Context Parameter section of the Parameters and Responses reference documentation.

Returns

To send a response, your function must return a properly formatted response dictionary. The following return types can be used in Go functions:

  • Use yourEventType to return a strongly typed result, where yourEventType is any type that can be unmarshalled using the encoding/json package. Make sure your struct has a field that can be rendered as a JSON body property to return data to the client.
  • Use map[string]interface to return any key-value pairs you want. Make sure that one of the keys is body to return data to the client.
  • Return no value if you do not need to return data to the client.

More details on the response can be found in the Returns section of the Parameters and Responses reference documentation.

Example Functions

Return JSON

If the body is a type that can be serializable as JSON by the encoding/json package, it is automatically serialized as JSON and returned with a Content-Type: application/json header.

package main

type Shark struct {
	Type string `json:"type"`
}

type Response struct {
	Body []Shark `json:"body"`
}

func Main() Response {
	return Response{
		Body: []Shark{
			{
				Type: "hammerhead",
			},
			{
				Type: "mako",
			},
		},
	}
}

Return an Image

To return an image or other media type, set the correct Content-Type header and return a base64-encoded body:

package main

type ResponseHeaders struct {
	ContentType string `json:"Content-Type"`
}

type Response struct {
	Body       string          `json:"body"`
	StatusCode string          `json:"statusCode"`
	Headers    ResponseHeaders `json:"headers"`
}

func Main() Response {
	// example 1x1 GIF
	gif := "R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
	return Response{
		Body:       gif,
		StatusCode: "200",
		Headers: ResponseHeaders{
			ContentType: "image/gif",
		},
	}
}

Return an HTTP Redirect

A 302 status code and location header redirects an HTTP client to a new URL:

package main

type ResponseHeaders struct {
	Location string `json:"location"`
}

type Response struct {
	StatusCode string          `json:"statusCode"`
	Headers    ResponseHeaders `json:"headers"`
}

func Main() Response {
	return Response{
		StatusCode: "302",
		Headers: ResponseHeaders{
			Location: "https://example.com",
		},
	}
}

Set cookies with the Set-Cookie header, and use the Content-Type: 'text/html' header to return HTML content:

package main

type ResponseHeaders struct {
	SetCookie   string `json:"Set-Cookie"`
	ContentType string `json:"Content-Type"`
}

type Response struct {
	Body       string          `json:"body"`
	StatusCode string          `json:"statusCode"`
	Headers    ResponseHeaders `json:"headers"`
}

func Main() Response {
	return Response{
		Body:       "<html><h1>Hello, World!</h1></html>",
		StatusCode: "200",
		Headers: ResponseHeaders{
			SetCookie:   "UserID=Sammy; Max-Age=3600; Version=",
			ContentType: "text/html",
		},
	}
}

More Example Functions

Some more in-depth example Go functions are available on GitHub:

github.com
github.com
github.com
github.com
github.com

Log to the Console

Any text output to stdout and stderr is logged and can be accessed through the doctl command line tool.

Log to stdout by using fmt.Print, fmt.Println, or other similar methods. Make sure to include a newline at the end of the message:

fmt.Print("this text is logged\n")

Use doctl serverless activations logs --follow to follow logs for all functions in the current namespace, or specify a single function with the --function flag.

See the doctl serverless activations logs reference for more information, or add the --help flag to the command for help output.

Use Modules and Dependencies

To use third-party Go modules, add a go.mod and go.sum file to the remote build process (Go functions are always built remotely during deploys).

First, navigate to the directory containing your function code.

Initialize your Go module if necessary (if you already have a go.mod file, skip this):

go mod init example

Add your third-party module, in this case the gosimple/slug module:

go get github.com/gosimple/slug

This creates the entries needed in go.mod and go.sum. The build process uses these files to download your third-party modules and build your function.

If you require different build steps you should create a build.sh file in the function directory. Read the Build Process reference for more details on the build process and build scripts.

Include Files in Built Function

To include arbitrary files with your deployed function (for example, config files and templates), you must use Go’s embed package. The files to be embedded must be placed in the same directory as the function source code files.

Here is an example function that embeds text content from a file:

Directory structure:

.
├── packages
│   └── <package-name>
│       └── <function-name>
│           ├── main.go
│           └── to_be_included.txt
└── project.yml
    
        
            
package main

import (
	_ "embed"
	"fmt"
)

//go:embed to_be_included.txt
var s string

type Response struct {
	Body string `json:"body"`
}

func Main() Response {
	return Response{
		Body: fmt.Sprintf("File contents: %q\n", s),
	}
}

        
    
    
        
            
Hello, World!

        
    

When invoked, the response is:

File contents: "Hello, World!"