Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AWS Lambda Go API Proxy (Echo v5 fork)

aws-lambda-go-api-proxy makes it easy to run Go APIs written with an HTTP framework on AWS Lambda, behind either Amazon API Gateway or an Application Load Balancer.

Why this fork exists

awslabs/aws-lambda-go-api-proxy was archived by its owner on May 21, 2025 and is now read-only. This fork exists because I needed two things the upstream project can no longer provide: support for Echo v5, and fixes for how ALB target group integration actually behaves.

It currently ships an Echo adapter only. I'm more than willing to add support for other frameworks — Gin, Fiber, Chi, GorillaMux, or anything else upstream carried — if there's interest from anyone else. Open an issue.

What's different from upstream

These are behavior changes. If you're coming from upstream, they're worth reading — three of the four fix failures that are close to invisible in production, because the Lambda runs fine, returns a well-formed response, and the client still gets a bare 502 with nothing logged to explain it.

  • Echo v5 instead of v4. Handlers take *echo.Context (a struct pointer), and path params use :name syntax.
  • ALB StatusDescription is emitted as "<code> <reason phrase>" (e.g. 500 Internal Server Error). Upstream sends the bare reason phrase, which ALB treats as a malformed target response and replaces with its own 502 page — on every response, regardless of status code.
  • ALB response header names are lowercased. ALB rejects canonically-cased names (Content-Type) the same way, with the same invisible 502.
  • ALB host resolution falls back to MultiValueHeaders. With multi-value headers enabled on the target group, ALB populates MultiValueHeaders and leaves Headers nil. Upstream reads Headers["host"] only, so every request resolved to an empty host.
  • core.GatewayTimeoutALB() sets a well-formed StatusDescription. Upstream leaves it empty.

Getting started

# First, install the Lambda go libraries.
go get github.com/aws/aws-lambda-go/events
go get github.com/aws/aws-lambda-go/lambda

# Next, install this library.
go get github.com/mshindle/aws-lambda-go-api-proxy/...

Requires Go 1.26+ and github.com/labstack/echo/v5.

Echo behind an ALB

ALB is what this fork is primarily maintained for. Declare an echoadapter.EchoLambdaALB in the global scope, initialize it in init with all your routes, and use ProxyWithContext to translate requests and responses.

package main

import (
	"context"

	"github.com/aws/aws-lambda-go/events"
	"github.com/aws/aws-lambda-go/lambda"
	"github.com/labstack/echo/v5"
	"github.com/mshindle/aws-lambda-go-api-proxy/echoadapter"
)

var albLambda *echoadapter.EchoLambdaALB

func init() {
	e := echo.New()
	e.GET("/ping", func(c *echo.Context) error {
		return c.String(200, "pong")
	})

	albLambda = echoadapter.NewALB(e)
}

func handler(ctx context.Context, req events.ALBTargetGroupRequest) (events.ALBTargetGroupResponse, error) {
	return albLambda.ProxyWithContext(ctx, req)
}

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

Enabling multi-value headers on the target group is supported and recommended — it's the only way to receive repeated request headers, and it's what the host-resolution fix above accounts for.

Echo behind API Gateway

Same shape, different constructor and event types. New handles API Gateway v1 (REST / proxy integration):

var echoLambda *echoadapter.EchoLambda

func init() {
	e := echo.New()
	e.GET("/ping", func(c *echo.Context) error {
		return c.String(200, "pong")
	})

	echoLambda = echoadapter.New(e)
}

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

NewV2 handles API Gateway v2 (HTTP APIs):

var echoLambdaV2 *echoadapter.EchoLambdaV2

func init() {
	e := echo.New()
	e.GET("/ping", func(c *echo.Context) error {
		return c.String(200, "pong")
	})

	echoLambdaV2 = echoadapter.NewV2(e)
}

func handler(ctx context.Context, req events.APIGatewayV2HTTPRequest) (events.APIGatewayV2HTTPResponse, error) {
	return echoLambdaV2.ProxyWithContext(ctx, req)
}

Request context

The ALB or API Gateway request context, stage variables, and the Lambda runtime context are populated into the request's context.Context automatically. Retrieve them with the core accessors:

// ALB
albCtx, ok := core.GetTargetGroupRequestFromContextALB(ctx)
rtCtx, ok := core.GetRuntimeContextFromContextALB(ctx)

log.Println(albCtx.ELB.TargetGroupArn)
log.Println(rtCtx.InvokedFunctionArn)

// API Gateway v1
apiGwCtx, ok := core.GetAPIGatewayContextFromContext(ctx)
stageVars, ok := core.GetStageVarsFromContext(ctx)

log.Println(apiGwCtx.RequestID)
log.Println(apiGwCtx.Stage)
log.Println(stageVars["MyStageVar"])

// API Gateway v2
apiGwV2Ctx, ok := core.GetAPIGatewayV2ContextFromContext(ctx)

Supporting other frameworks

Alongside the adapters, this library declares a core package containing utility methods and interfaces that translate Lambda proxy events into Go's standard http.Request and http.ResponseWriter objects. Adding a framework means wiring those to that framework's http.Handler.

Using the ALB adapter as the worked example: echoadapter/adapterALB.go embeds the RequestAccessorALB struct defined in core/requestALB.go, which provides ProxyEventToHTTPRequest() and EventToRequestWithContext().

EchoLambdaALB is initialized with an *echo.Echo, which implements http.Handler. Its Proxy method receives an events.ALBTargetGroupRequest, converts it to an *http.Request, creates a ProxyResponseWriterALB (defined in core/responseALB.go), and passes both to the framework's ServeHTTP. ProxyResponseWriterALB.GetProxyResponse() then produces the events.ALBTargetGroupResponse from whatever was written.

Support for any other framework relies on the same core methods, swapping *echo.Echo for that framework's handler type. Contributions welcome.

License

This library is licensed under the Apache 2.0 License.

About

Update of the awslabs repository which had been archived.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages