DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • How to Document Your AWS Cloud Infrastructure Using Multicloud-Diagrams Framework
  • Unleashing the Power of AWS: Revolutionizing Cloud Management Through Infrastructure as Code (IaC)
  • Top 9 Role-Based Cloud Certifications for Solution Architects in 2024
  • How To Understand and Choose Your First EC2 Instance on AWS

Trending

  • AI-Based Threat Detection in Cloud Security
  • The Modern Data Stack Is Overrated — Here’s What Works
  • Scalable System Design: Core Concepts for Building Reliable Software
  • Unlocking AI Coding Assistants Part 3: Generating Diagrams, Open API Specs, And Test Data

How Do I Run My Go Applications in a Serverless Way?

In this tutorial, learn how to run Go REST APIs as Lambda functions using the AWS Lambda Go API Proxy.

By 
Abhishek Gupta user avatar
Abhishek Gupta
DZone Core CORE ·
Jul. 25, 23 · Tutorial
Likes (2)
Comment
Save
Tweet
Share
10.1K Views

Join the DZone community and get the full member experience.

Join For Free

The Go programming language has always had rich support for building REST APIs. This includes an excellent standard library (net/HTTP) along with many popular packages such as Gorilla mux, Gin, Negroni, Echo, Fiber, etc.

Using AWS Lambda Go runtime, you can use Go to build AWS Lambda functions. Imagine a web app that needs to authenticate users, store user data, and send emails. A Serverless approach for this would be to implement each functionality/API as a separate Lambda function. For example, you could have a Lambda function to handle user registration, another to handle user login, and so on.

This is great if you are building everything from scratch. But what if you wanted to run existing Go REST APIs as AWS Lambda functions?

Broadly speaking, you would need to:

  1. Split the existing code into multiple Lambda functions.
  2. Refactor each of them to work with AWS Lambda Go runtime APIs.

With the AWS Lambda Go API Proxy, there is an easier way.

This blog will demonstrate how to run existing Go frameworks-based APIs in a serverless way with AWS Lambda and Amazon API Gateway. You will walk through simple code examples for the net/http package, and gorilla and echo frameworks to understand how they work and deploy them using AWS Serverless Application Model.

The code is available in this GitHub repository.

Let's start with a brief introduction to the AWS Lambda Go API Proxy.

AWS Lambda Go API Proxy: How Does It Work?

The aws-lambda-go-api-proxy package makes it easy to run Go APIs written using frameworks (such as Gin) with AWS Lambda and Amazon API Gateway. In addition to adapter implementations for the net/http (Go standard library) and other frameworks such as gorilla/mux, echo, etc., aws-lambda-go-api-proxy also declares a core package that contains utility methods and interfaces to translate API Gateway proxy events into Go's default http.Request and http.ResponseWriter objects and allows you to adapt any framework to the AWS Lambda Go runtime.

How does the AWS Lambda Go API Proxy work

Here is a gist of how it works at a high level:

  1. The API Gateway request is accepted by the Lambda function handler.
  2. The function handler proxies the request to the adapter implementation corresponding to the framework.
  3. Finally, the API Gateway proxy response is returned to the client.

Let's look into the framework-specific behavior.

gorilla/mux Library

Package gorilla/mux implements a request router and dispatcher for matching incoming requests to their respective handler. Like http.ServeMux in the Go standard library, mux.Router matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. Because gorilla/mux implements the http.Handler interface, it is compatible with http.ServeMux.

Here is a simple example of a Lambda function that uses an adapter implementation to work with gorilla/mux package:

var gorillaLambda *gorillamux.GorillaMuxAdapter

func init() {
    r := mux.NewRouter()

    r.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode(Response{From: "gorilla", Message: time.Now().Format(time.UnixDate)})
    })

    gorillaLambda = gorillamux.New(r)
}

func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    r, err := gorillaLambda.ProxyWithContext(ctx, *core.NewSwitchableAPIGatewayRequestV1(&req))
    return *r.Version1(), err
}

func main() {
    lambda.Start(Handler)
}


  • In the init function: gorillamux.New function takes in a mux.Router (which has the HTTPGET route defined) and returns a gorillamux.GorillaMuxAdapter.
  • In the Handlerimplementation:
    • The Proxy (or ProxyWithContext) method of the gorillamux.GorillaMuxAdapter object receives the events.APIGatewayProxyRequest, converts it into a http.Request object, and sends it to the mux.Router for routing.
    • It returns a proxy response object (events.APIGatewayProxyResponse) generated from the data written to the response writer (http.ResponseWriter).

Echo Framework

Echo is another popular Go web framework that is minimalist, yet highly extensible.

Here is a simple example of a Lambda function that uses an adapter implementation to work with the echo framework:

var echoLambda *echoadapter.EchoLambda

func init() {
    e := echo.New()

    e.Use(middleware.Logger())
    e.Use(middleware.Recover())

    e.GET("/ping", func(c echo.Context) error {
        return c.JSON(http.StatusOK, Response{From: "echo", Message: time.Now().Format(time.UnixDate)})
    })

    echoLambda = echoadapter.New(e)
}

func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
    return echoLambda.ProxyWithContext(ctx, req)
}

func main() {
    lambda.Start(Handler)
}


The concept is similar to the previous example.

  • The init function sets up the router (echo.Echo) and passes it into the echoadapter.New thar returns a echoadapter.EchoLambda (the adapter implementation).
  • In the Handlerfunction:
    • The ProxyWithContext method of the echoadapter.EchoLambda object receives the events.APIGatewayProxyRequest object and converts it into an http.Request object and sends it to echo.Echo for routing.
    • It returns a proxy response object (events.APIGatewayProxyResponse) generated from the data written to the response writer (http.ResponseWriter).

net/http Package

The adapter implementation for net/http also works the same way. Here is the code snippet:

var httpLambda *httpadapter.HandlerAdapter

func init() {
    http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
        json.NewEncoder(w).Encode(Response{From: "net/http", Message: time.Now().Format(time.UnixDate)})
    })

    httpLambda = httpadapter.New(http.DefaultServeMux)
}

func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {

    return httpLambda.ProxyWithContext(ctx, req)
}

func main() {
    lambda.Start(Handler)
}


  • To use with the standard library, the httpadapter.New function takes in a http.Handler (which has the route defined) and returns a httpadapter.HandlerAdapter object.
  • The ProxyWithContent method on the httpadapter.HandlerAdapter can then be used as a Lambda handler.

Let's see how this works in practice.

Deploy to AWS Lambda

Let's deploy each of these functions to AWS Lambda using the SAM CLI.

Prerequisites

Before you proceed, make sure you have the Go programming language (v1.18 or higher) and AWS SAM installed.

Clone the project and change it to the right directory:

git clone https://github.com/build-on-aws/golang-apis-on-aws-lambda

cd golang-apis-on-aws-lambda


gorilla/mux-Based Lambda Function

First, update the CodeUri in template.yaml to gorilla/ (which is the local folder where the code is located).

Build the function:

sam build

#expected output

Building codeuri: <path>/lambda-go-api-proxy-getting-started/gorilla runtime: go1.x metadata: {} architecture: x86_64 functions: DemoFunction
Running GoModulesBuilder:Build

Build Succeeded
....


Deploy the function (follow the SAM CLI prompts):

export STACK_NAME=lambda-go-gorilla

sam deploy --stack-name $STACK_NAME --guided

# response to the prompts

Stack Name [lambda-go-gorilla]: <press enter>
AWS Region [us-east-1]: <enter alternate region or press enter>
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: n
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: n
DemoFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]: <press enter>
SAM configuration environment [default]: <press enter>


Once the deployment is complete, navigate to AWS CloudFormation console to check the deployed stack and associated resources. These include the Lambda function, API Gateway (REST API), IAM role, etc.

AWS CloudFormation console to check the deployed stack and associated resource

You should see the API Gateway endpoint as the SAM CLI output (it will be different in your case) or the CloudFormation Outputs section.

-----------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------
Outputs                                                                                                
--------------------------------------------------------------------------------------------------------
Key                 APIGWEndpoint                                                                   
Description         API Gateway Endpoint                                                                                                
Value               https://whrd2yy3ug.execute-api.us-east-1.amazonaws.com/dev/ping                    
--------------------------------------------------------------------------------------------------------

Successfully created/updated stack - lambda-go-gorilla in us-east-1


To test the function, invoke the API Gateway using the following command:

export API_ENDPOINT=<enter the API Gateway endpoint here>

curl $API_ENDPOINT


You should get a JSON response similar to the following:

{
  "from": "gorilla",
  "message": "Tue Jun 27 18:10:54 UTC 2023"
}


net/http and echo-Based Lambda Functions

Before you deploy either of these, make sure to update the CodeUri in template.yaml to refer to the local folder where the code is located:

  • http-stdlib/ in case of net/http package.
  • echo/ in case of echo framework.

Build and deploy the function (respond to the prompts, just like before):

sam build

# change the stack name to lambda-go-echo in case of "echo" framework
export STACK_NAME=lambda-go-nethttp

sam deploy --stack-name $STACK_NAME --guided


You can test the function by invoking the API Gateway endpoint:

export API_ENDPOINT=<enter your API endpoint here>

curl $API_ENDPOINT


You should get a JSON response similar to the following:

{
  "from": "net/http",
  "message": "Tue Jun 27 18:20:42 UTC 2023"
}


In case of echo framework, you should get a JSON response similar to the following (notice the different name in the from field):

{
  "from": "echo",
  "message": "Tue Jun 27 18:30:25 UTC 2023"
}


That's it! You have successfully deployed your Go APIs as AWS Lambda functions.

Cleanup

Once you are done, delete the stacks:

sam delete --stack-name lambda-go-gorilla
sam delete --stack-name lambda-go-nethttp
sam delete --stack-name lambda-go-echo


Conclusion

This blog post introduced you to the AWS Lambda Go API Proxy, and how its framework/package (for gorilla/mux, echo and net/http) specific adapter implementations allow you to run existing Go applications as AWS Lambda functions fronted by an API Gateway. You learned the basic concepts with simple code examples, deployed these functions using AWS SAM CLI, and verified it by invoking the API Gateway endpoint.

The AWS Lambda Go API Proxy also supports Gin, which is one of the most popular Go web frameworks. The second part of this blog will demonstrate how to run existing Gin framework-based Go applications as AWS Lambda functions with the help of a simple (yet practical) URL shortener service.

Stay tuned!

AWS Cloud

Published at DZone with permission of Abhishek Gupta, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • How to Document Your AWS Cloud Infrastructure Using Multicloud-Diagrams Framework
  • Unleashing the Power of AWS: Revolutionizing Cloud Management Through Infrastructure as Code (IaC)
  • Top 9 Role-Based Cloud Certifications for Solution Architects in 2024
  • How To Understand and Choose Your First EC2 Instance on AWS

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!