Skip to content

Commit

Permalink
Merge pull request #61 from nao1215/feat/lambda-api
Browse files Browse the repository at this point in the history
Lambda with API Gateway
  • Loading branch information
nao1215 authored Feb 9, 2024
2 parents fadaeee + 192e6e6 commit bfabb1d
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ The s3hub command provides following features:
|Name|README|implementation|
|:--|:--|:--|
|[Lambda batch with EventBridge (CloudWatch Events)](./cloudformation/lambda-batch/README.md)||100%|
|[Lambda with API Gateway](./cloudformation/api-gateway-with-lambda/README.md)||100%|
|[CloudWatch Real User Monitoring (RUM)](./cloudformation/cloudwatch-rum/README.md)||100%|


Expand Down
1 change: 1 addition & 0 deletions cloudformation/api-gateway-with-lambda/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bootstrap
28 changes: 28 additions & 0 deletions cloudformation/api-gateway-with-lambda/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.DEFAULT_GOAL := help

BINARY_NAME = bootstrap
AWS_STACK_NAME = lambda-batch
TEMPLATE_FILE = template.yml

.PHONY: help clean dependency_check build deploy
help: ## Show this help message
@grep -E '^[0-9a-zA-Z_-]+[[:blank:]]*:.*?## .*$$' $(MAKEFILE_LIST) | sort \
| awk 'BEGIN {FS = ":.*?## "}; {printf "\033[1;32m%-15s\033[0m %s\n", $$1, $$2}'

clean: ## Clean project
-rm -rf $(BINARY_NAME)

dependency_check: ## Check dependencies
@command -v sam > /dev/null 2>&1 || { echo "Error: sam is not installed. See https://github.com/aws/aws-sam-cli"; exit 1; }

build: ## Build binary
@echo "Building for Lambda execution environment (Linux/ARM64)"
GOOS=linux GOARCH=arm64 go build -o $(BINARY_NAME) main.go

deploy: dependency_check build ## Deploy CloudFormation Template
sam deploy --stack-name $(AWS_STACK_NAME) --template-file $(TEMPLATE_FILE) \
--capabilities CAPABILITY_IAM --resolve-s3 --region ap-northeast-1 || { echo "SAM deployment failed"; exit 1; }

test-deploy: build ## Deploy CloudFormation Template for test
samlocal deploy --stack-name $(AWS_STACK_NAME) --template-file $(TEMPLATE_FILE) \
--capabilities CAPABILITY_IAM --resolve-s3 --region ap-northeast-1 || { echo "SAM deployment failed"; exit 1; }
39 changes: 39 additions & 0 deletions cloudformation/api-gateway-with-lambda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## API Gateway with Lambda
### Overview

Lambda and API Gateway combined infrastructure is a powerful means for realizing serverless architecture. Lambda is a service for executing code, while API Gateway creates HTTP endpoints and forwards requests to Lambda functions.

![lambda-with-apigateway](./lambda-with-apigateway.png)

This combination offers the following characteristics:

- Simplified Serverless Architecture: Combining API Gateway with Lambda allows for the creation of a serverless architecture, eliminating issues with server management and scaling.
- Cost Efficiency: Being billed only for the resources you use, costs can scale with traffic, reducing wasteful spending.
- Seamless Integration: API Gateway provides seamless integration with Lambda, allowing you to define API endpoints and route requests to Lambda functions.
- Facilitates the implementation of microservices architecture, allowing deployment of independent Lambda functions for each functionality.

### Limitations
- Long Processing Time: Lambda functions are limited by execution time. If long processing is required, Lambda might not be suitable. Alternative methods should be explored for long-running processes.
- Heavy Data Processing: Lambda functions have resource limits. For tasks requiring heavy data processing or significant memory, other services or architectures might be more suitable.
- Always Active Services: Lambda is event-driven and goes to sleep when there are no requests. For services that need to be always active or for background processing, Lambda might not be appropriate.


### How to deploy
> [!NOTE]
> Before running `make deploy`, ensure you have configured AWS credentials and set the correct region. Otherwise, you use single sign-on (SSO).
```shell
$ make deploy
```

### Endpoint Base URL Syntax
The URL syntax for the API Gateway endpoint is as follows:

```
https://<api-id>.execute-api.<region>.amazonaws.com/<stage>
```

- `<api-id>`: The API Gateway ID.
- `<region>`: The AWS region where the API Gateway is deployed.
- `<stage>`: The stage name of the API Gateway.

Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<mxfile host="65bd71144e">
<diagram id="XGAyPcSnOJNRtPWJga0X" name="ページ1">
<mxGraphModel dx="1297" dy="347" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="827" pageHeight="1169" background="#ffffff" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="29" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;fontSize=16;fontColor=#000000;strokeColor=#000000;" parent="1" target="27" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-29" y="211" as="sourcePoint"/>
</mxGeometry>
</mxCell>
<mxCell id="26" value="&lt;font color=&quot;#000000&quot;&gt;&lt;span style=&quot;font-size: 16px;&quot;&gt;API Gateway&lt;/span&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="-164.5" y="261" width="193" height="30" as="geometry"/>
</mxCell>
<mxCell id="33" style="edgeStyle=none;html=1;strokeColor=#000000;" parent="1" source="27" target="32" edge="1">
<mxGeometry relative="1" as="geometry"/>
</mxCell>
<mxCell id="27" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F78E04;gradientDirection=north;fillColor=#D05C17;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.lambda;" parent="1" vertex="1">
<mxGeometry x="173" y="172" width="78" height="78" as="geometry"/>
</mxCell>
<mxCell id="28" value="&lt;font color=&quot;#000000&quot;&gt;&lt;span style=&quot;font-size: 16px;&quot;&gt;Lambda&lt;/span&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="115.5" y="261" width="193" height="30" as="geometry"/>
</mxCell>
<mxCell id="30" value="&lt;div style=&quot;text-align: start;&quot;&gt;&lt;font face=&quot;Söhne, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Helvetica Neue, Arial, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji&quot; color=&quot;#000000&quot;&gt;&lt;span style=&quot;font-size: 16px; background-color: rgb(255, 255, 255);&quot;&gt;invoke&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="-24" y="181" width="193" height="30" as="geometry"/>
</mxCell>
<mxCell id="32" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#F34482;gradientDirection=north;fillColor=#BC1356;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.cloudwatch_2;" parent="1" vertex="1">
<mxGeometry x="173" y="28" width="78" height="78" as="geometry"/>
</mxCell>
<mxCell id="34" value="&lt;span style=&quot;font-family: Söhne, ui-sans-serif, system-ui, -apple-system, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, Cantarell, &amp;quot;Noto Sans&amp;quot;, sans-serif, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255);&quot;&gt;&lt;font style=&quot;&quot; color=&quot;#000000&quot;&gt;CloudWatch&lt;/font&gt;&lt;/span&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="251" y="76" width="104" height="30" as="geometry"/>
</mxCell>
<mxCell id="35" value="&lt;span style=&quot;font-family: Söhne, ui-sans-serif, system-ui, -apple-system, &amp;quot;Segoe UI&amp;quot;, Roboto, Ubuntu, Cantarell, &amp;quot;Noto Sans&amp;quot;, sans-serif, &amp;quot;Helvetica Neue&amp;quot;, Arial, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;, &amp;quot;Segoe UI Symbol&amp;quot;, &amp;quot;Noto Color Emoji&amp;quot;; font-size: 16px; text-align: start; background-color: rgb(255, 255, 255);&quot;&gt;&lt;font style=&quot;&quot; color=&quot;#000000&quot;&gt;Logging&lt;/font&gt;&lt;/span&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
<mxGeometry x="135" y="124" width="78" height="30" as="geometry"/>
</mxCell>
<mxCell id="36" value="" style="sketch=0;points=[[0,0,0],[0.25,0,0],[0.5,0,0],[0.75,0,0],[1,0,0],[0,1,0],[0.25,1,0],[0.5,1,0],[0.75,1,0],[1,1,0],[0,0.25,0],[0,0.5,0],[0,0.75,0],[1,0.25,0],[1,0.5,0],[1,0.75,0]];outlineConnect=0;fontColor=#232F3E;gradientColor=#FF4F8B;gradientDirection=north;fillColor=#BC1356;strokeColor=#ffffff;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;shape=mxgraph.aws4.resourceIcon;resIcon=mxgraph.aws4.api_gateway;" vertex="1" parent="1">
<mxGeometry x="-107" y="172" width="78" height="78" as="geometry"/>
</mxCell>
<mxCell id="41" style="edgeStyle=none;html=1;strokeColor=#2c1c1c;" edge="1" parent="1" source="40">
<mxGeometry relative="1" as="geometry">
<mxPoint x="-108" y="211" as="targetPoint"/>
</mxGeometry>
</mxCell>
<mxCell id="40" value="" style="sketch=0;outlineConnect=0;fontColor=#232F3E;gradientColor=none;fillColor=#232F3D;strokeColor=none;dashed=0;verticalLabelPosition=bottom;verticalAlign=top;align=center;html=1;fontSize=12;fontStyle=0;aspect=fixed;pointerEvents=1;shape=mxgraph.aws4.user;" vertex="1" parent="1">
<mxGeometry x="-319" y="172" width="78" height="78" as="geometry"/>
</mxCell>
<mxCell id="42" value="&lt;div style=&quot;text-align: start;&quot;&gt;&lt;font face=&quot;Söhne, ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, Helvetica Neue, Arial, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji&quot; color=&quot;#000000&quot;&gt;&lt;span style=&quot;font-size: 16px; background-color: rgb(255, 255, 255);&quot;&gt;Request&lt;/span&gt;&lt;/font&gt;&lt;/div&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
<mxGeometry x="-266" y="179" width="193" height="30" as="geometry"/>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 37 additions & 0 deletions cloudformation/api-gateway-with-lambda/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package main

import (
"context"
"encoding/json"
"log"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)

// HealthResponse struct defines the response structure
type HealthResponse struct {
Status string `json:"status"`
}

// Handler is the Lambda function handler
func Handler(_ context.Context) (events.APIGatewayProxyResponse, error) {
// Create a response
responseBody, err := json.Marshal(HealthResponse{Status: "healthy"})
if err != nil {
log.Printf("Error marshaling JSON response: %v", err)
return events.APIGatewayProxyResponse{StatusCode: 500, Body: `{"error":"Internal Server Error"}`}, nil
}

// Return API Gateway response
return events.APIGatewayProxyResponse{
StatusCode: 200,
Headers: map[string]string{"Content-Type": "application/json"},
Body: string(responseBody),
}, nil
}

func main() {
// Start the Lambda handler
lambda.Start(Handler)
}
71 changes: 71 additions & 0 deletions cloudformation/api-gateway-with-lambda/template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
AWSTemplateFormatVersion: "2010-09-09"
Transform:
- AWS::Serverless-2016-10-31
Description: "API Gateway with Lambda"

Resources:
LambdaFuncttion:
Type: "AWS::Serverless::Function"
Properties:
FunctionName: lambda-function
Handler: "handler"
Runtime: provided.al2
Architectures: [arm64]
Timeout: 10
CodeUri: ./
MemorySize: 128
Policies:
- AWSLambdaBasicExecutionRole
Events:
GetApi:
Type: Api
Properties:
Path: /health
Method: get
RestApiId: !Ref API

API:
Type: "AWS::Serverless::Api"
Properties:
Name: sam-test-get-api
EndpointConfiguration: REGIONAL
StageName: dev

LambdaLogGroup:
Type: "AWS::Logs::LogGroup"
DeletionPolicy: Retain
UpdateReplacePolicy: Retain
Properties:
LogGroupName: !Sub "/aws/lambda/${LambdaFuncttion}"
RetentionInDays: 7
KmsKeyId: !GetAtt LambdaLogGroupKMSKey.Arn

LambdaLogGroupKMSKey:
Type: AWS::KMS::Key
UpdateReplacePolicy: Retain
DeletionPolicy: Retain
Properties:
Description: "KMS key for encrypting CloudWatch Logs"
EnableKeyRotation: true
KeyPolicy:
Version: "2012-10-17"
Id: "key-default"
Statement:
- Sid: "Allow administration of the key"
Effect: "Allow"
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
Action:
- "kms:*"
Resource: "*"
- Sid: "Allow use of the key"
Effect: "Allow"
Principal:
Service: "logs.ap-northeast-1.amazonaws.com"
Action:
- "kms:Encrypt"
- "kms:Decrypt"
- "kms:ReEncrypt*"
- "kms:GenerateDataKey*"
- "kms:DescribeKey"
Resource: "*"
25 changes: 23 additions & 2 deletions cloudformation/lambda-batch/template.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Resources:
Properties:
LogGroupName: !Sub "/aws/lambda/${LambdaBatch}"
RetentionInDays: 7
KmsKeyId: !Ref LambdaLogGroupKMSKey
KmsKeyId: !GetAtt LambdaLogGroupKMSKey.Arn

LambdaLogGroupKMSKey:
Type: AWS::KMS::Key
Expand All @@ -62,4 +62,25 @@ Resources:
Properties:
Description: "KMS key for encrypting CloudWatch Logs"
EnableKeyRotation: true

KeyPolicy:
Version: "2012-10-17"
Id: "key-default"
Statement:
- Sid: "Allow administration of the key"
Effect: "Allow"
Principal:
AWS: !Sub "arn:aws:iam::${AWS::AccountId}:root"
Action:
- "kms:*"
Resource: "*"
- Sid: "Allow use of the key"
Effect: "Allow"
Principal:
Service: "logs.ap-northeast-1.amazonaws.com"
Action:
- "kms:Encrypt"
- "kms:Decrypt"
- "kms:ReEncrypt*"
- "kms:GenerateDataKey*"
- "kms:DescribeKey"
Resource: "*"

0 comments on commit bfabb1d

Please sign in to comment.