
GoLang vanity urls on AWS Lambda
March 21, 2019
After the article on the reasons to use vanity URLs in Go and the one about how to implement a lightweight vanity URLs provider, I’d like to share with you how you can leverage AWS Lambda to implement a vanity URLs provider.
The first thing we will need is to import the github.com/aws/aws-lambda-go
package.
This package will provide us with the needed functions to easily integrate our Go code with AWS Lambda.
In our main
we will just need to start the Lambda with a handler like this:
func main() {
lambda.Start(Handler)
}
We then need to define the handler itself.
Due to how the Start
function works, we are fairly free to decide how many parameters to accept and return.
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
for _, c := range conversions {
if request.Path[1:] == c.Vanity || strings.HasPrefix(request.Path[1:], c.Vanity+"/") {
var tplOutput bytes.Buffer
if err := tpl.Execute(&tplOutput, c); err != nil {
return events.APIGatewayProxyResponse{Body: err.Error(), StatusCode: 500}, nil
}
return events.APIGatewayProxyResponse{Body: tplOutput.String(), StatusCode: 200}, nil
}
}
return events.APIGatewayProxyResponse{Body: "Not found", StatusCode: 404}, nil
}
We now need an HTML template called tpl
to add all the needed HTML tags that the Go dependency downloader needs:
var tpl = template.Must(template.New("main").Parse(`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="{{ .Domain }}/{{ .Vanity }} git {{ .Real }}">
</head>
</html>
`))
We also need to define the slice of objects conversions
and its base type:
type conversion struct {
Vanity string
Real string
Domain string
}
var conversions = []conversion{
conversion{Domain: "go.kelfa.io", Vanity: "aws-cloudfront-logCompactor", Real: "https://github.com/kelfa/aws-cloudfront-logCompactor"},
conversion{Domain: "go.kelfa.io", Vanity: "elf", Real: "https://github.com/kelfa/elf"},
conversion{Domain: "go.kelfa.io", Vanity: "go.kelfa.io", Real: "https://github.com/kelfa/go.kelfa.io"},
}
The conversions
slice values are to be tweaked based on the packages the AWS Lambda function will need to handle.
The whole code together would be:
package main
import (
"bytes"
"html/template"
"strings"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
type conversion struct {
Vanity string
Real string
Domain string
}
var conversions = []conversion{
conversion{Domain: "go.kelfa.io", Vanity: "aws-cloudfront-logCompactor", Real: "https://github.com/kelfa/aws-cloudfront-logCompactor"},
conversion{Domain: "go.kelfa.io", Vanity: "elf", Real: "https://github.com/kelfa/elf"},
conversion{Domain: "go.kelfa.io", Vanity: "go.kelfa.io", Real: "https://github.com/kelfa/go.kelfa.io"},
}
var tpl = template.Must(template.New("main").Parse(`<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta name="go-import" content="{{ .Domain }}/{{ .Vanity }} git {{ .Real }}">
</head>
</html>
`))
func Handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
for _, c := range conversions {
if request.Path[1:] == c.Vanity || strings.HasPrefix(request.Path[1:], c.Vanity+"/") {
var tplOutput bytes.Buffer
if err := tpl.Execute(&tplOutput, c); err != nil {
return events.APIGatewayProxyResponse{Body: err.Error(), StatusCode: 500}, nil
}
return events.APIGatewayProxyResponse{Body: tplOutput.String(), StatusCode: 200}, nil
}
}
return events.APIGatewayProxyResponse{Body: "Not found", StatusCode: 404}, nil
}
func main() {
lambda.Start(Handler)
}
We still have to overcome a small AWS Lambda-specific hurdle: the creation of the function itself. To do so, we can run in a terminal:
GOOS=linux go build main.go
zip function.zip main
aws lambda update-function-code --function-name go-kelfa-io --zip-file fileb://function.zip
rm main
rm function.zip
Those commands will allow us to compile the function in the proper form and upload the code to the function called go-kelfa-io
.
The name will need to be changed to your specific usage.
Also, remember that the update-function-code
command expects the AWS Lambda function to be already present in your account and the aws
CLI tool to be configured appropriately.
I hope this helps other people looking for an easy and very cheap way of hosting their own Go packages with vanity URLs.