Last active
January 5, 2024 11:05
-
-
Save Paulo-Lopes-Estevao/3ac5fe6420f1d5bd9cdd91266b52d440 to your computer and use it in GitHub Desktop.
AWS Lambda and API Gateway using Terraform.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWS Lambda functions and API gateway are often used to create serverless applications. | |
Function code is written in Go and deployed using Terraform. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resource "aws_apigatewayv2_api" "lambda_api_gateway" { | |
name = var.apigatewayv2_api_main.name | |
protocol_type = var.apigatewayv2_api_main.protocol_type | |
} | |
resource "aws_apigatewayv2_stage" "lambda_api_gateway_stage" { | |
api_id = aws_apigatewayv2_api.lambda_api_gateway.id | |
name = "dev" | |
auto_deploy = true | |
access_log_settings { | |
destination_arn = aws_cloudwatch_log_group.api_gw.arn | |
format = jsonencode({ | |
requestId = "$context.requestId" | |
sourceIp = "$context.identity.sourceIp" | |
requestTime = "$context.requestTime" | |
protocol = "$context.protocol" | |
httpMethod = "$context.httpMethod" | |
resourcePath = "$context.resourcePath" | |
routeKey = "$context.routeKey" | |
status = "$context.status" | |
responseLength = "$context.responseLength" | |
integrationErrorMessage = "$context.integrationErrorMessage" | |
} | |
) | |
} | |
} | |
resource "aws_apigatewayv2_integration" "lambda_api_gateway_integration" { | |
api_id = aws_apigatewayv2_api.lambda_api_gateway.id | |
integration_type = "AWS_PROXY" | |
integration_method = "POST" | |
integration_uri = aws_lambda_function.lambda_handler.invoke_arn | |
} | |
resource "aws_apigatewayv2_route" "get_lambda_api_gateway_route" { | |
api_id = aws_apigatewayv2_api.lambda_api_gateway.id | |
route_key = "GET /hello" | |
target = "integrations/${aws_apigatewayv2_integration.lambda_api_gateway_integration.id}" | |
} | |
resource "aws_cloudwatch_log_group" "api_gw" { | |
name = "/aws/apigateway/${aws_apigatewayv2_api.lambda_api_gateway.name}" | |
retention_in_days = 7 | |
} | |
resource "aws_lambda_permission" "lambda_api_gateway_permission" { | |
statement_id = "AllowExecutionFromAPIGateway" | |
action = "lambda:InvokeFunction" | |
function_name = aws_lambda_function.lambda_handler.function_name | |
principal = "apigateway.amazonaws.com" | |
source_arn = "${aws_apigatewayv2_api.lambda_api_gateway.execution_arn}/*/*" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resource "aws_s3_bucket" "lambda_bucket" { | |
bucket = random_pet.lambda_bucket_name.id | |
} | |
resource "aws_s3_bucket_ownership_controls" "lambda_bucket_ownership_controls" { | |
bucket = aws_s3_bucket.lambda_bucket.id | |
rule { | |
object_ownership = "BucketOwnerPreferred" | |
} | |
} | |
resource "aws_s3_bucket_acl" "lambda_bucket_acl" { | |
depends_on = [aws_s3_bucket_ownership_controls.lambda_bucket_ownership_controls] | |
bucket = aws_s3_bucket.lambda_bucket.id | |
acl = "private" | |
} | |
resource "aws_s3_object" "lambda_handler_bucket_object" { | |
bucket = aws_s3_bucket.lambda_bucket.id | |
key = "handler.zip" | |
source = data.archive_file.lambda_handler_archive_file.output_path | |
etag = filemd5(data.archive_file.lambda_handler_archive_file.output_path) | |
depends_on = [ | |
data.archive_file.lambda_handler_archive_file, | |
] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resource "aws_lambda_function" "lambda_handler" { | |
function_name = "LambdaHandler" | |
role = aws_iam_role.lambda_role.arn | |
handler = "app" | |
source_code_hash = data.archive_file.lambda_handler_archive_file.output_base64sha256 // or filebase64sha256(handler.zip) | |
runtime = "go1.x" | |
s3_bucket = aws_s3_bucket.lambda_bucket.id | |
s3_key = aws_s3_object.lambda_handler_bucket_object.key | |
depends_on = [ | |
aws_s3_object.lambda_handler_bucket_object, | |
] | |
} | |
resource "aws_cloudwatch_log_group" "lambda_cloudwatch_log" { | |
name = "/aws/lambda/${aws_lambda_function.lambda_handler.function_name}" | |
retention_in_days = 14 | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"encoding/json" | |
"github.com/aws/aws-lambda-go/events" | |
"github.com/aws/aws-lambda-go/lambda" | |
"log" | |
"net/http" | |
) | |
type Africa struct { | |
Flag string `json:"flag"` | |
Location string `json:"location"` | |
Keywords []string `json:"keywords"` | |
Name string `json:"name"` | |
Capital string `json:"capital"` | |
Currency string `json:"currency"` | |
Language string `json:"language"` | |
Population float64 `json:"population"` | |
Area float64 `json:"area"` | |
Callingcode string `json:"callingcode"` | |
} | |
func HandleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (*events.APIGatewayV2HTTPResponse, error) { | |
log.Println("Start handler") | |
var africa []Africa | |
err := json.Unmarshal(data, &africa) | |
if err != nil { | |
return errResponse(http.StatusInternalServerError, err.Error()), nil | |
} | |
return response(http.StatusOK, africa), nil | |
} | |
func response(code int, data []Africa) *events.APIGatewayV2HTTPResponse { | |
marshalled, err := json.Marshal(data) | |
if err != nil { | |
return errResponse(http.StatusInternalServerError, err.Error()) | |
} | |
return &events.APIGatewayV2HTTPResponse{ | |
StatusCode: code, | |
Headers: map[string]string{ | |
"Content-Type": "application/json", | |
}, | |
Body: string(marshalled), | |
IsBase64Encoded: false, | |
} | |
} | |
func errResponse(status int, body string) *events.APIGatewayV2HTTPResponse { | |
message := map[string]string{ | |
"message": body, | |
} | |
messageBytes, _ := json.Marshal(&message) | |
return &events.APIGatewayV2HTTPResponse{ | |
StatusCode: status, | |
Headers: map[string]string{ | |
"Content-Type": "application/json", | |
}, | |
Body: string(messageBytes), | |
} | |
} | |
func main() { | |
log.Println("Start lambda") | |
lambda.Start(HandleRequest) | |
} | |
var data = []byte(` | |
[ | |
{ | |
"flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/af/Flag_of_South_Africa.svg/200px-Flag_of_South_Africa.svg.png", | |
"location": "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a1/LocationSouthAfrica.svg/300px-LocationSouthAfrica.svg.png", | |
"keywords": ["ZA", "South Africa"], | |
"name": "África do Sul", | |
"capital": "Cape Town", | |
"currency": "Rand", | |
"language": "Inglês", | |
"population": 0, | |
"area": 0, | |
"callingcode": "+27" | |
}, | |
{ | |
"flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/9/9d/Flag_of_Angola.svg/200px-Flag_of_Angola.svg.png", | |
"location": "https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/LocationAngola.svg/300px-LocationAngola.svg.png", | |
"keywords": ["AO"], | |
"name": "Angola", | |
"capital": "Luanda", | |
"currency": "Kwanza", | |
"language": "Português", | |
"population": 0, | |
"area": 0, | |
"callingcode": "+244" | |
}, | |
{ | |
"flag": "https://upload.wikimedia.org/wikipedia/commons/thumb/7/77/Flag_of_Algeria.svg/200px-Flag_of_Algeria.svg.png", | |
"location": "https://upload.wikimedia.org/wikipedia/commons/thumb/b/b8/LocationAlgeria.svg/300px-LocationAlgeria.svg.png", | |
"keywords": ["DZ"], | |
"name": "Argélia", | |
"capital": "Algiers", | |
"currency": "Dinar argelino", | |
"language": "Árabe", | |
"population": 0, | |
"area": 0, | |
"callingcode": "+213" | |
} | |
]`) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
provider "aws" { | |
region = var.aws_region | |
default_tags { | |
tags = { | |
tag_name = "lambda-api-gateway" | |
} | |
} | |
} | |
data "archive_file" "lambda_handler_archive_file" { | |
type = "zip" | |
source_dir = "${path.module}/handler" | |
output_path = "${path.module}/handler.zip" | |
} | |
resource "random_pet" "lambda_bucket_name" { | |
prefix = "lambda-bucket" | |
length = 4 | |
} | |
resource "aws_iam_role" "lambda_role" { | |
name = "handler-lambda-role" | |
assume_role_policy = <<EOF | |
{ | |
"Version": "2012-10-17", | |
"Statement": [ | |
{ | |
"Action": "sts:AssumeRole", | |
"Principal": { | |
"Service": "lambda.amazonaws.com" | |
}, | |
"Effect": "Allow", | |
"Sid": "" | |
} | |
] | |
} | |
EOF | |
} | |
resource "aws_iam_role_policy_attachment" "lambda_role_policy" { | |
role = aws_iam_role.lambda_role.name | |
policy_arn = var.iam_role_policy_arn | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
build: | |
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -v -ldflags='-d -s -w' -a -tags netgo -installsuffix netgo -o handler/app handler/main.go && \ | |
chmod +x handler/app | |
init: | |
terraform init | |
validate: | |
terraform validate | |
plan: | |
terraform plan | |
apply: | |
terraform apply --auto-approve | |
destroy: | |
terraform destroy --auto-approve | |
.PHONY: build init validate plan apply | |
LAMBDA_NAME=LambdaHandler | |
invoke-lambda: | |
aws lambda invoke --region=us-east-1 --function-name $(LAMBDA_NAME) response.json |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
output "lambda_role" { | |
description = "IAM role for the lambda function." | |
value = aws_iam_role.lambda_role | |
} | |
output "lambda_bucket_object" { | |
description = "S3 bucket object for the lambda handler." | |
value = aws_s3_object.lambda_handler_bucket_object | |
} | |
output "function_name" { | |
description = "Name of the lambda function." | |
value = aws_lambda_function.lambda_handler.function_name | |
} | |
output "base_url" { | |
description = "Base URL for the API Gateway v2 API." | |
value = aws_apigatewayv2_api.lambda_api_gateway.api_endpoint | |
} | |
output "get_base_url" { | |
value = aws_apigatewayv2_stage.lambda_api_gateway_stage.invoke_url | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
terraform { | |
required_providers { | |
aws = { | |
source = "hashicorp/aws" | |
version = "~> 4.15.0" | |
} | |
random = { | |
source = "hashicorp/random" | |
version = "~> 3.1.0" | |
} | |
archive = { | |
source = "hashicorp/archive" | |
version = " 2.4.0" | |
} | |
} | |
required_version = "~> 1.2" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
variable "aws_region" { | |
description = "AWS region for all resources." | |
type = string | |
default = "us-east-1" | |
} | |
variable "iam_role_policy_arn" { | |
description = "ARN of the IAM role policy to attach to the lambda role." | |
type = string | |
default = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" | |
} | |
variable "apigatewayv2_api_main" { | |
description = "API Gateway v2 API for the main API." | |
type = object({ | |
name = string | |
protocol_type = string | |
}) | |
default = { | |
name = "main" | |
protocol_type = "HTTP" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment