What is Serverless Architecture?
Serverless architecture is a way to build and run applications and services without having to manage infrastructure. Your application still runs on servers, but all the server management is done by AWS.
AWS Lambda
AWS Lambda
is a serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers. You can trigger Lambda from over 200 AWS services and software as a service (SaaS) applications and only pay for what you use.
Advantages of Using AWS Lambda
- Run code without provisioning or managing infrastructure. Simply write and upload code as a
.zip
file or container image. - Automatically respond to code execution requests at any scale, from a dozen events per day to hundreds of thousands per second.
- Save costs by paying only for computing time you use — by per millisecond — instead of provisioning infrastructure upfront for peak capacity.
- Optimize code execution time and performance with the right function memory size. Respond to high demand in double-digit milliseconds with Provisioned Concurrency.
Serverless Application in Go with AWS
Prerequisites
- You’ll need an AWS account for this. If you don’t yet have one, sign up for a free account here.
- For building and deploying your functions, you’ll be using the
Serverless Framework
, which is the most widely used tool for the job. Assuming you have a recent version of Node.js installed, you can install theServerless CLI
with the following npm command:
$ npm install -g serverless
Once you have the Serverless CLI installed, you must configure it to use the AWS access keys of your account:
$ serverless config credentials --provider aws --key <access key ID> --secret <secret access key>
You can get the access key and secret key from the My Security Credentials
option. Use Create New Access Key
if you do not have one already.
- If you don’t have Go installed yet, you can either download an installer from the official website or use your favorite package manager to install it
The Lambda-Time Function
Now that you have everything you need, let’s create a new project using Go modules for your function. For example, let’s name the module lambda-time
. In a new, empty directory, initialize the Go module, and install the AWS Lambda for Go library:
$ go mod init lambda-time
$ go get github.com/aws/aws-lambda-go
After this, you can proceed to create a main.go
file that implements your handler function and starts the process:
package main
import (
"context"
"encoding/json"
"log"
"time"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func main() {
lambda.Start(handleRequest)
}
func handleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
resp := &response{
UTC: time.Now().UTC(),
}
body, err := json.Marshal(resp)
if err != nil {
return events.APIGatewayProxyResponse{}, err
}
return events.APIGatewayProxyResponse{Body: string(body), StatusCode: 200}, nil
}
type response struct {
UTC time.Time `json:"utc"`
}
This previous code can be broken into a few simple steps:
- Define a response struct that supports JSON serialization and defines the HTTP response body of a successful invocation of your AWS Lambda function.
- Create a request handler function, which creates a response struct containing the current time in UTC and then proceeds to serialize it as JSON. In case the serialization fails, you return the error; if everything goes well, you respond with your serialized JSON as the response body and a status code of 200.
- Register your handler function in the main function using the
AWS Lambda for Go library
.
The Handler Function
It’s worth taking some time to understand how the handler function works. While there are multiple valid handler signatures, the one you used is the complete one. The context argument provides information on the invoked function, its environment and the deadline of the invocation. Returning an error value from the handler function signals that the invocation failed and automatically logs the value of the error.
That leaves the request and response structs in your handler function signature. Lambda functions are invoked either by AWS services or by using an AWS SDK
(e.g., from another Lambda function). Data passed in and out of a Lambda function is in JSON format. In your case, the AWS Lambda for Go
library automatically handles the serialization and deserialization between JSON and Go values.
When calling Lambda functions using the AWS SDK, the structure of the input and output JSON data is up to the developer. For AWS Lambda functions invoked by AWS services, the data structure depends on the invoking service. Amazon API Gateway
is the service that triggers Lambda functions in response to HTTP calls. For API Gateway, this means the request is always of type events.APIGatewayProxyRequest
and the response will always be of type events.APIGatewayProxyResponse
.
The AWS Lambda for Go
library contains the data definitions for each AWS service that can invoke Lambda functions.
Integration with Golang Routing Libraries
If you are using some package for routing, there is a package available that may be used to connect their routing library with lambda.
github.com/awslabs/aws-lambda-go-api-proxy
It currently supports the following routing libraries.
- chi
- gin
- gorillamux
- fiber
- echo
- iris
- negroni
Lets see the chi
example for routing:
package main
import (
"context"
"encoding/json"
"log"
"time"
chiadapter "github.com/awslabs/aws-lambda-go-api-proxy/chi"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func main() {
lambda.Start(handleRequests)
}
func handleRequests(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
router := chi.NewRouter()
router.Get("/", func (w http.ResponseWriter, _ *http.Request) {
resp := &response{
UTC: time.Now().UTC(),
}
body, err := json.Marshal(resp)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
w.WriteHeader(http.StatusOK)
w.Write(body)
})
return chiadapter.New(router).ProxyWithContext(ctx, req)
}
type response struct {
UTC time.Time `json:"utc"`
}
Deployment
Your function is now ready and you can proceed by deploying it with the Serverless Framework. Your application deployed using the Serverless framework based on the serverless.yml
configuration file.
If you are not familiar with the .yml
syntax, you can read this serverless.yml guide.
We must first create a serverless.yml
file that defines what we are deploying.
service: lambda-time
provider:
name: aws
runtime: go1.x
package:
exclude:
- ./**
include:
- ./bin/**
functions:
lambda-time:
handler: bin/lambda-time
events:
- http:
path: /
method: get
Here you name both your service and the function lambda-time
, but the service could instead contain multiple functions with different names. You also need to configure your API Gateway by specifying that the function responds to HTTP events of a particular HTTP method and at a given request path.
Next up, build the code as an x86-64 Linux executable, and deploy it:
$ GOOS=linux GOARCH=amd64 go build -o bin/lambda-time .
$ serverless deploy
Once finished, the command prints the URL for the endpoint.
Open it, and make sure it responds with the current time.
Now you can visit your aws account. You can see your application at AWS services
> Lambda
> Applications
In your application you can see your ApiGatewayRestApi
, Lambda Function
and ServerlessDeploymentBucket
where your api is deployed.
In ApiGatewayRestApi
there are api paths Method Execution
where you can run Test.
Stage
where you can create multiple stages, By Default we have a dev stage.
In Lambda Functions
you can see your lambda functions and in your function there is runtime settings
where your handler file and runtime language already selected.
Let's visit Cloud Watch
where you can see your logs:
References
- Go Support for AWS Lambda
- AWS Lambda and Golang
- AWS Lambda function handler in Go
- Serverless Architecture
See full source-code at this github repository.
Top comments (0)