Create an AWS lambda function in Go
Introduction
In this article we will create a lambda function and an API Gateway route like we did with the serverless framework but only using AWS tools, we will be using the same generated code for our function from the last article What does the serverless framework does for me, so refer to that one before starting this one if you want to know how did we get here. Also as a side note this is a very basic example on how to get started with lambda without any additional tool.
Let’s see the code one more time
package main
import (
"bytes"
"context"
"encoding/json"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
// Response is of type APIGatewayProxyResponse since we're leveraging the
// AWS Lambda Proxy Request functionality (default behavior)
//
// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration
type Response events.APIGatewayProxyResponse
// Handler is our lambda handler invoked by the `lambda.Start` function call
func Handler(ctx context.Context) (Response, error) {
var buf bytes.Buffer
body, err := json.Marshal(map[string]interface{}{
"message": "Go Serverless v1.0! Your function executed successfully!",
})
if err != nil {
return Response{StatusCode: 404}, err
}
json.HTMLEscape(&buf, body)
resp := Response{
StatusCode: 200,
IsBase64Encoded: false,
Body: buf.String(),
Headers: map[string]string{
"Content-Type": "application/json",
"X-MyCompany-Func-Reply": "hello-handler",
},
}
return resp, nil
}
func main() {
lambda.Start(Handler)
}
With that code as a starting point, now we need to build, package, upload, and deploy our function:
Build
GOOS=linux go build main.go
Package
zip main.zip ./main
# OUTPUT:
# adding: main (deflated 51%)
Create the role
Go to IAM > Roles > Create. Then select Lambda, assign a name and a description and then get the ARN for this role. Note that with the serverless framework this is done automatically for us, so we don’t need to create a new role for each
Upload / Deploy
aws lambda create-function \
--region us-east-1 \
--function-name helloworld \
--memory 128 \
--role arn:aws:iam::894527626897:role/testing-aws-go \
--runtime go1.x \
--zip-file fileb://main.zip \
--handler main
# OUTPUT:
# {
# "FunctionName": "helloworld",
# "FunctionArn": "arn:aws:lambda:us-east-1:894527626897:function:helloworld",
# "Runtime": "go1.x",
# "Role": "arn:aws:iam::894527626897:role/testing-aws-go",
# "Handler": "main",
# "CodeSize": 4346283,
# "Description": "",
# "Timeout": 3,
# "MemorySize": 128,
# "LastModified": "2019-02-16T15:44:10.610+0000",
# "CodeSha256": "02/PQBeQuCC8JS1TLjyU38oiUwiyQSmKJXjya25XpFA=",
# "Version": "$LATEST",
# "TracingConfig": {
# "Mode": "PassThrough"
# },
# "RevisionId": "7c9030e5-4a26-4f7e-968d-3a4f65dfde21"
# }
Note that your function-name must match the name of your Lambda handler name (Handler). Note that this role might be insecure in some scenarios if you grant too much permissions, so try to restrict it as much as possible as with any role and policy.
Test the function
aws lambda invoke --function-name helloworld --log-type Tail /dev/stdout
# OUTPUT:
# {"statusCode":200,"headers":{"Content-Type":"application/json","X-MyCompany-Func-Reply":"hello-handler"},"body":"{\"message\":\"Go Serverless v1.0! Your function executed successfully!\"}"}{
# "StatusCode": 200,
# "LogResult": "U1RBUlQgUmVxdWVzdElkOiBmZTRmMWE4Zi1kYzAyLTQyYWQtYjBlYy0wMjA5YjY4MDY1YWQgVmVyc2lvbjogJExBVEVTVApFTkQgUmVxdWVzdElkOiBmZTRmMWE4Zi1kYzAyLTQyYWQtYjBlYy0wMjA5YjY4MDY1YWQKUkVQT1JUIFJlcXVlc3RJZDogZmU0ZjFhOGYtZGMwMi00MmFkLWIwZWMtMDIwOWI2ODA2NWFkCUR1cmF0aW9uOiAxMy4xOSBtcwlCaWxsZWQgRHVyYXRpb246IDEwMCBtcyAJTWVtb3J5IFNpemU6IDEyOCBNQglNYXggTWVtb3J5IFVzZWQ6IDQ1IE1CCQo=",
# "ExecutedVersion": "$LATEST"
# }
Everything looks about right, so what’s next? We will eventually need to communicate with this code from an external source, so let’s see how we can do that with the API Gateway. Also the log is encoded in base64, so if you want to see what the log result was do the following.
Check the logs
echo "U1RBUlQgUmVxdWVzdElkOiBmZTRmMWE4Zi1kYzAyLTQyYWQtYjBlYy0wMjA5YjY4MDY1YWQgVmVyc2lvbjogJExBVEVTVApFTkQgUmVxdWVzdElkOiBmZTRmMWE4Zi1kYzAyLTQyYWQtYjBlYy0wMjA5YjY4MDY1YWQKUkVQT1JUIFJlcXVlc3RJZDogZmU0ZjFhOGYtZGMwMi00MmFkLWIwZWMtMDIwOWI2ODA2NWFkCUR1cmF0aW9uOiAxMy4xOSBtcwlCaWxsZWQgRHVyYXRpb246IDEwMCBtcyAJTWVtb3J5IFNpemU6IDEyOCBNQglNYXggTWVtb3J5IFVzZWQ6IDQ1IE1CCQo=" | base64 -d
# OUTPUT:
# START RequestId: fe4f1a8f-dc02-42ad-b0ec-0209b68065ad Version: $LATEST
# END RequestId: fe4f1a8f-dc02-42ad-b0ec-0209b68065ad
# REPORT RequestId: fe4f1a8f-dc02-42ad-b0ec-0209b68065ad Duration: 13.19 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 45 MB
You should also be able to see this same output in CloudWatch.
API Gateway
To make this step simpler I decided to use the AWS Console instead of the CLI it will also cut down the size of this article substantially.
Now we need to create the API Gateway endpoint
Note that you only have to go to Lambda->Functions->helloworld->Add triggers->API Gateway. And then complete as shown in the image, when you save this new trigger you will get the resource that then can be used to test the API Gateway integration.
The endpoint will show as follows (Click on API Gateway):
Test the API
curl -v https://r8efasfb26.execute-api.us-east-1.amazonaws.com/default/helloworld
# OUTPUT:
# * Trying 54.236.123.239...
# * TCP_NODELAY set
# * Connected to r8efasfb26.execute-api.us-east-1.amazonaws.com (54.236.123.239) port 443 (#0)
# * ALPN, offering h2
# * ALPN, offering http/1.1
# * successfully set certificate verify locations:
# * CAfile: /etc/ssl/certs/ca-certificates.crt
# CApath: none
# * TLSv1.3 (OUT), TLS handshake, Client hello (1):
# * TLSv1.3 (IN), TLS handshake, Server hello (2):
# * TLSv1.2 (IN), TLS handshake, Certificate (11):
# * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
# * TLSv1.2 (IN), TLS handshake, Server finished (14):
# * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
# * TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
# * TLSv1.2 (OUT), TLS handshake, Finished (20):
# * TLSv1.2 (IN), TLS handshake, Finished (20):
# * SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
# * ALPN, server accepted to use h2
# * Server certificate:
# * subject: CN=*.execute-api.us-east-1.amazonaws.com
# * start date: Sep 20 00:00:00 2018 GMT
# * expire date: Oct 20 12:00:00 2019 GMT
# * subjectAltName: host "r8efasfb26.execute-api.us-east-1.amazonaws.com" matched cert's "*.execute-api.us-east-1.amazonaws.com"
# * issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
# * SSL certificate verify ok.
# * Using HTTP2, server supports multi-use
# * Connection state changed (HTTP/2 confirmed)
# * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
# * Using Stream ID: 1 (easy handle 0x56394c766db0)
# > GET /default/helloworld HTTP/2
# > Host: r8efasfb26.execute-api.us-east-1.amazonaws.com
# > User-Agent: curl/7.63.0
# > Accept: */*
# >
# * Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
# < HTTP/2 200
# < date: Sat, 16 Feb 2019 17:17:58 GMT
# < content-type: application/json
# < content-length: 70
# < x-amzn-requestid: ce5c5863-320e-11e9-9e76-875e7540974c
# < x-amz-apigw-id: VM_XAGhoIAMFqoQ=
# < x-mycompany-func-reply: hello-handler
# < x-amzn-trace-id: Root=1-5c6845c6-920cfc7da3cfd94f3e644647;Sampled=0
# <
# * Connection #0 to host r8efasfb26.execute-api.us-east-1.amazonaws.com left intact
# {"message":"Go Serverless v1.0! Your function executed successfully!"}
If you ask me that was a lot of effort to handle without automation, maybe AWS SAM or the serverless framework can make things easier and let you focus on your application rather than the boilerplate required for it to run.
Clean up
Always remember to clean up and delete everything that you created (to avoid surprises and save money), in this article I will leave that as an exercise for the reader :)
Errata
If you spot any error or have any suggestion, please send me a message so it gets fixed.
Also, you can check the source code and changes in the generated code and the sources here
-
Comments
Online: 0
Please sign in to be able to write comments.