Serverless application in golang with AWS (Lambda Service)
Tags: aws, serverless, lambda, go
Published: 2022-11-21 07:30:26

## 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


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7r5o0icie6avcmtngil5.png)

### Prerequisites

- You’ll need an AWS account for this. If you don’t yet have one, [sign up for a free account here](https://aws.amazon.com/free/?all-free-tier.sort-by=item.additionalFields.SortRank&all-free-tier.sort-order=asc&awsf.Free%20Tier%20Types=*all&awsf.Free%20Tier%20Categories=*all).
- 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](https://nodejs.org/en/) installed, you can install the `Serverless CLI` with the following npm command:

  ```console
  $ npm install -g serverless
  ```

  Once you have the Serverless CLI installed, you must configure it to use the AWS access keys of your account:

  ```console
  $ 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.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eezfmrfnwe4cx40089iy.png)

- If you don’t have Go installed yet, you can either [download an installer](https://golang.org/dl/) 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](https://github.com/aws/aws-lambda-go) library:

```console
$ 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:

```go
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](https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html), 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:

```go
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](https://bref.sh/docs/environment/serverless-yml.html).

We must first create a `serverless.yml` file that defines what we are deploying.

```yaml
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:

```console
$ GOOS=linux GOARCH=amd64  go build -o bin/lambda-time .
$ serverless deploy
```

Once finished, the command prints the URL for the endpoint.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/40ofk3pt2fxaf7u4gpvz.png)

Open it, and make sure it responds with the current time.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t1gwu1rrikg49d0gnzhz.png)

Now you can visit your aws account. You can see your application at `AWS services` > `Lambda` > `Applications`


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/eta60jthvwq7j53mpx4r.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cuxu9qfqic95d5qjcyto.png)

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.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/csjsaheb40rsc7ifbx2p.png)

`Stage` where you can create multiple stages, By Default we have a dev stage.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zazldh6moer02kk1nvar.png)

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.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hs66upyuu712egq1sqbo.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/799b9e7mpp1tl3qaoy4h.png)


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fdgnry1vakf1g3z1v6zb.png)

Let's visit `Cloud Watch` where you can see your logs:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8458jz1vb8byfa1odcn8.png)

## References

- [Go Support for AWS Lambda](https://aws.amazon.com/blogs/compute/announcing-go-support-for-aws-lambda/)
- [AWS Lambda and Golang](https://epsagon.com/development/getting-started-with-aws-lambda-and-go/)
- [AWS Lambda function handler in Go](https://docs.aws.amazon.com/lambda/latest/dg/golang-handler.html)
- [Serverless Architecture](https://aws.amazon.com/lambda/serverless-architectures-learn-more/)

See full source-code at [this github repository](https://github.com/datumbrain/go-serverless-aws-lambda-example).