How do I run existing Go applications on AWS Lambda - Part 2
Learn how to take a URL shortener application written using Gin and run it as a serverless AWS Lambda function.
gorilla/mux
, echo
and net/http
) allows you to run existing Go applications as AWS Lambda functions fronted by Amazon API Gateway. If you haven't already, I encourage you to take a look at it in order to get a basic understanding of the AWS Lambda Go API Proxy.Gin
framework, and run it as a serverless AWS Lambda function. Instead of using AWS SAM, we will change things up a bit and use the AWS CDK to deploy the solution.The code is available on GitHub
aws-lambda-go-api-proxy
package makes it possible to run Go APIs written using Gin, thanks to the framework specific adapter implementations.main.go
file of the Lambda function:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var ginLambda *ginadapter.GinLambda
func init() {
r := gin.Default()
r.POST("/app", CreateShortURL)
r.GET("/app/:shortcode", GetShortURL)
r.DELETE("/app/:shortcode", DeleteShortURL)
r.PUT("/app/:shortcode", UpdateStatus)
ginLambda = ginadapter.New(r)
}
func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return ginLambda.ProxyWithContext(ctx, req)
}
func main() {
lambda.Start(Handler)
}
- In the
init
function:- We use
gin.Default()
to create agin.Engine
object with theLogger
andRecovery
middleware already attached. - We create routes by associating a
gin.HandlerFunc
with eachHTTP
method and path using thePOST
,GET
,DELETE
andPUT
methods of thegin.Engine
object. ginadapter.New
function takes this*gin.Engine
object and returns aginadapter.GinLambda
.
- In the
Handler
implementation:- The
Proxy
(orProxyWithContext
) method of theginadapter.GinLambda
object receives theevents.APIGatewayProxyRequest
, converts it into ahttp.Request
object, and sends it to thegin.Engine
for routing. - It returns a proxy response object (
events.APIGatewayProxyResponse
) generated from the data written to the response writer (http.ResponseWriter
).
bit.ly
or other solutions you may have used. It uses Amazon DynamoDB for persistence and exposes HTTP
endpoints to access the application (basic CRUD operations).1
2
3
4
5
6
7
.
├── db
│ └── db.go
├── go.mod
├── go.sum
├── handler.go
├── main.go
- The
db
package contains code to interact withDynamoDB
. - The
handler.go
file has the implementation for theHTTP
methods. - The
main.go
file creates the Gin engine with the routes andginadapter.GinLambda
object to proxy requests and responses.
1
2
3
git clone https://github.com/build-on-aws/golang-gin-app-on-aws-lambda
cd golang-gin-app-on-aws-lambda
You can refer to the code in the cdk directory.
cdk deploy
command. You will see a list of resources that will be created and will need to provide your confirmation to proceed.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cd cdk
cdk deploy
# output
Bundling asset LambdaGolangProxyAPIDemoStack/gin-go-lambda-function/Code/Stage...
✨ Synthesis time: 5.94s
This deployment will make potentially sensitive changes according to your current security approval level (--require-approval broadening).
Please confirm you intend to make the following modifications:
//.... omitted
Do you wish to deploy these changes (y/n)? y
y
to start creating the AWS resources required for the application. This will start creating the AWS resources required for our application.If you want to see the AWS CloudFormation template which will be used behind the scenes, runcdk synth
and check thecdk.out
folder
CloudFormation > Stacks > LambdaGolangProxyAPIDemoStack
- A Lambda function.
- A DynamoDB table to store application data.
- And a few other components (like
IAM
roles etc.).
CloudFormation
console for your stack). It should look something like this - https://foobarbazl.execute-api.us-east-1.amazonaws.com/prod/
HTTP
POST
request (for e.g. https://abhirockzz.github.io/
)1
2
3
4
5
6
7
# e.g. export URL_SHORTENER_APP_URL=https://foobarbazl.execute-api.us-east-1.amazonaws.com/prod/app
export URL_SHORTENER_APP_URL=<replace with API Gateway endpoint above>/app
# invoke the endpoint to create short code
curl -i -X POST -d '{"url":"https://abhirockzz.github.io/"}' $URL_SHORTENER_APP_URL
curl -i -X POST -d '{"url":"https://abhishek1987.medium.com/"}' $URL_SHORTENER_APP_URL
curl -i -X POST -d '{"url":"https://dzone.com/users/456870/abhirockzz.html"}' $URL_SHORTENER_APP_URL
HTTP 201
along with the short code in the HTTP
response (as a JSON
payload).1
2
3
4
5
6
HTTP/2 201
content-type: text/plain; charset=utf-8
content-length: 25
apigw-requestid: VTzPsgmSoAMESdA=
{"short_code":"1ee3ad1b"}
<URL_SHORTENER_APP_URL>/app/<generated short code>
for e.g. https://8zbqx074rl.execute-api.us-east-1.amazonaws.com/prod/app/4b824fad
curl
1
curl -i $URL_SHORTENER_APP_URL/app/1ee3ad1b
HTTP
302
response (Found
) and the URL redirection happens due to the Location
HTTP
header which has the original URL.1
2
3
4
5
6
# some of the headers omitted for brevity
HTTP/2 302
content-type: application/json
content-length: 0
location: https://abhirockzz.github.io
....
1
2
3
export URL_SHORTENER_APP_URL=<replace with API Gateway endpoint above>/app
curl -i -X PUT -d '{"active": false}' -H 'Content-Type: application/json' $URL_SHORTENER_APP_URL/3626fb51
HTTP
PUT
request with a JSON payload that specifies the status (false
in this case refers to disable
action) along with the short code which is a path parameter to the API Gateway endpoint. If all works well, you should see an HTTP 204
(No Content
) response.false
.1
2
3
export URL_SHORTENER_APP_URL=<replace with API Gateway endpoint above>/app
curl -i -X DELETE $URL_SHORTENER_APP_URL/<short code>
HTTP 204
response. But this time, the respective DynamoDB record will be deleted.- Access a disabled URL.
- Enable a disabled URL (use
{"active": true}
). - Access an invalid short code (that does not exist).
1
cdk destroy
main.go
in this case) to wire up the Gin router (gin.Engine
) to a Lambda function handler (entry point) by using the adapter implementation for Gin.SeriesToc |
---|
Any opinions in this post are those of the individual author and may not reflect the opinions of AWS.