DEV Community

Cover image for Serverless Framework example for Golang and Lambda
We're Serverless! for Serverless Inc.

Posted on • Originally published at serverless.com

3 1

Serverless Framework example for Golang and Lambda

Originally posted at Serverless

Here’s how you can start using Go with the Serverless Framework RIGHT NOW and deploy Lambdas to your heart’s content.

Get Started

First things first, you’ll be needing the Serverless Framework installed, and an AWS account.

(If it’s your first time using the Serverless Framework, our first time deployment post has a quick setup guide. Takes like 5 minutes, we promise.)

Use the Go template

The Framework will configure AWS for Go on your behalf.

There are a couple Go templates already included with the Framework as of v1.26 — aws-go for a basic service with two functions, and aws-go-dep for the basic service using the dep dependency management tool. Let's try the aws-go-dep template. You will need **dep installed.**

Make sure you’re in your ${GOPATH}/src directory, then run:

$ serverless create -t aws-go-dep -p myservice
view raw .sh hosted with ❤ by GitHub

Change into your new service directory and compile the function:
$ cd myservice
$ make
view raw .sh hosted with ❤ by GitHub

The default command in the included Makefile will gather your dependencies and build the proper binaries for your functions. You can deploy now:
$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (4.43 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
........................
Serverless: Stack update finished...
Service Information
service: myservice
stage: dev
region: us-east-1
stack: myservice-dev
api keys:
None
endpoints:
None
functions:
hello: myservice-dev-hello
world: myservice-dev-world
view raw serverless.sh hosted with ❤ by GitHub

Finally, invoke your function:
$ serverless invoke -f hello
{
"message": "Go Serverless v1.0! Your function executed successfully!"
}
view raw serverless.sh hosted with ❤ by GitHub

Nice!

Building a Web API with Go + Lambda

The basic example is nice, but let’s try something a little more useful.

Lambda + API Gateway is awesome for quickly spinning up endpoints to retrieve or ingest data. So we’re going to build an example endpoint.

For our friends coming from interpreted, dynamically-typed languages (looking at you, Pythonistas & Javascript-lovers!), the Golang approach is a little different. You have to be a more intentional about the input & output of your functions. Don’t worry, we’ll take it slow. 😉

We’re going to make an HTTP endpoint that accepts a POST request at the path /echo, logs the POST body, and echoes the body back to the client.

First, let’s fix our serverless.yml to attach an HTTP event:

# serverless.yml
service: myservice
provider:
name: aws
runtime: go1.x
package:
exclude:
- ./**
include:
- ./bin/**
functions:
hello:
handler: bin/hello
events:
- http:
path: hello
method: post
view raw serverless.yml hosted with ❤ by GitHub

We’ll need to update our function in hello/main.go.

Remember, Golang is a compiled, statically-typed language, so we need to define the event object that's coming into our function. Fortunately, AWS has provided a number of event types in a Github repo. 💥 We can just use those.

Update your hello/main.go to have the following code:

# hello/main.go
package main
import (
"fmt"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
fmt.Println("Received body: ", request.Body)
return events.APIGatewayProxyResponse{Body: request.Body, StatusCode: 200}, nil
}
func main() {
lambda.Start(Handler)
}
view raw hello.go hosted with ❤ by GitHub

Our Handler() function now takes an APIGatewayProxyRequest object and returns a APIGatewayProxyResponse object. In our function code, we're printing the request body, then returning a response with the request body.

Recompile & deploy again:

$ make
dep ensure
env GOOS=linux go build -ldflags="-s -w" -o bin/hello hello/main.go
env GOOS=linux go build -ldflags="-s -w" -o bin/world world/main.go
$ sls deploy
Serverless: Packaging service...
... <snip> ...
...............................
Serverless: Stack update finished...
Service Information
service: myservice
stage: dev
region: us-east-1
stack: myservice-dev
api keys:
None
endpoints:
POST - https://24k8pql1le.execute-api.us-east-1.amazonaws.com/dev/hello
functions:
hello: myservice-dev-hello
world: myservice-dev-world
view raw deploy.sh hosted with ❤ by GitHub

Notice that you now have an endpoint listed in your Service Information output.

Let’s use curl to hit your endpoint and get a response:

$ curl -X POST https://24k8pql1le.execute-api.us-east-1.amazonaws.com/dev/hello -d 'Hello, world!'
Hello, world!
view raw .sh hosted with ❤ by GitHub

Great! This should get you started on a web API. Feel free to check out the other Lambda events in Golang.

Why use Go for your Lambdas?

Golang support for Lambda has been one of the most anticipated releases. The crowd at re:Invent was ecstatic when Werner announced Golang support was coming soon.

Why do people care about Golang so much? Simple: the combination of safety + speed.

As we saw above, Golang is a compiled, statically-typed language. This can help catch simple errors and maintain correctness as your application grows. This safety is really useful for production environments.

However, we’ve had Java and C# support in Lambda for years. These are both compiled, static languages as well. What’s the difference?

Java and C# both have notoriously slow cold-start time, in terms of multiple seconds. With Go, the cold-start time is much lower. In my haphazard testing, I was seeing cold-starts in the 200–400ms range, which is much closer to Python and Javascript.

Speed and safety. A pretty nice combo.

A Gateway to all the runtimes

There’s one final note about the Golang implementation on Lambda that’s really interesting.

The main() function which is the entrypoint to our Golang binary isn't our Lambda handler function. It's a little RPC server that wraps our handler function:

func main() {
lambda.Start(Handler)
}
view raw .go hosted with ❤ by GitHub

Under the covers, it looks like Lambda starts up your executable on a coldstart. The executable listens on a given port, receives input via JSON, and sends a response via JSON.

This opens up a lot of possibilities to bring other runtimes into Lambda. You just need to pull in an executable that implements the desired RPC interface.

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more