Go编程语言一直以来都对构建REST API提供了丰富的支持。这包括一个出色的标准库(net/HTTP),以及许多流行的包,如Gorilla mux、Gin、Negroni、Echo、Fiber等。使用AWS Lambda Go运行时,我们可以使用Go构建AWS Lambda函数。想象一下,一个Web应用程序需要对用户进行身份验证、存储用户数据和发送电子邮件。采用无服务器的方法,可以将每个功能/API实现为单独的Lambda函数。例如,我们可以有一个Lambda函数来处理用户注册,另一个来处理用户登录,依此类推。如果我们从头开始构建一切,这很好。但是,如果我们想将现有的Go REST API作为AWS Lambda函数运行,该怎么办呢?大体上来说,您需要进行以下操作:
- 将现有的代码拆分为多个Lambda函数。
- 重构每个函数以适配AWS Lambda Go运行时API。
不过使用AWS Lambda Go API Proxy,有一种更简单的方法。 接下来将演示如何使用AWS Lambda和Amazon API Gateway以无服务器方式运行基于Go框架的现有API。将通过简单的代码示例和框架来了解它们的工作原理,并使用AWS Serverless Application Model(SAM)部署它们。代码可在此GitHub存储库中找到。让我们从AWS Lambda Go API Proxy的简要介绍开始。
AWS Lambda Go API Proxy:它是如何工作的?
aws-lambda-go-api-proxy包使得使用框架(如Gin)编写的Go API能够轻松地在AWS Lambda和Amazon API Gateway上运行。除了适配器实现(针对Go标准库)和其他框架(如,,等)外,aws-lambda-go-api-proxy还声明了一个包,其中包含了将API Gateway代理事件转换为Go默认和对象的实用方法和接口,并允许您将任何框架适配到AWS Lambda Go运行时中。
下面是它的高级工作原理概述:
- Lambda函数处理程序接收API Gateway的请求。
- 函数处理程序将请求代理到与框架对应的适配器实现。
- 最后,将API Gateway代理响应返回给客户端。
再让我们深入了解一下特定于框架的行为。
gorilla/mux库
gorilla/mux包实现了一个请求路由器和调度器,用于将传入的请求与其相应的处理程序进行匹配。与Go标准库中的类似,它将传入的请求与注册的路由列表进行匹配,并调用与URL或其他条件匹配的路由的处理程序。由于实现了接口与其他的兼容。下面有一个简单的Lambda函数示例,使用适配器实现与gorilla/mux包一起使用:
var gorillaLambda *gorillamux.GorillaMuxAdapter
func init() {
r := mux.NewRouter()
r.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(Response{From: "gorilla", Message: time.Now().Format(time.UnixDate)})
})
gorillaLambda = gorillamux.New(r)
}
func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
r, err := gorillaLambda.ProxyWithContext(ctx, *core.NewSwitchableAPIGatewayRequestV1(&req))
return *r.Version1(), err
}
func main() {
lambda.Start(Handler)
}
在这个函数中:函数接收一个 http.Request
对象(其中定义了路由),并返回一个 http.Response
对象。在实现中:Handler
对象的 ServeHTTP
方法接收 http.Request
对象,将其转换为 http.ResponseWriter
对象,并将其发送到路由器进行路由处理。它将根据写入到响应写入器的数据生成一个代理响应对象(http.Response
)。
Echo框架
Echo是另一个流行的Go Web框架,它既简约又高度可扩展。下面是一个简单的Lambda函数示例,使用适配器实现与Echo框架一起使用:
var echoLambda *echoadapter.EchoLambda
func init() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
e.GET("/ping", func(c echo.Context) error {
return c.JSON(http.StatusOK, Response{From: "echo", Message: time.Now().Format(time.UnixDate)})
})
echoLambda = echoadapter.New(e)
}
func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return echoLambda.ProxyWithContext(ctx, req)
}
func main() {
lambda.Start(Handler)
}
该函数设置了一个路由器(echo.Echo
),并将其传递给 echoadapter.New
函数,返回一个适配器实现(echoadapter.EchoLambda
)。在函数中:Handler
对象的 ProxyWithContext
方法接收 events.APIGatewayProxyRequest
对象,并将其转换为 http.Request
对象,然后将其发送到 echo.Echo
进行路由处理。它将根据写入到响应写入器的数据生成一个代理响应对象(events.APIGatewayProxyResponse
)。
net/http
对于net/http包,适配器实现的工作方式也是相同的。以下是代码片段的示例:
var httpLambda *httpadapter.HandlerAdapter
func init() {
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(Response{From: "net/http", Message: time.Now().Format(time.UnixDate)})
})
httpLambda = httpadapter.New(http.DefaultServeMux)
}
func Handler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
return httpLambda.ProxyWithContext(ctx, req)
}
func main() {
lambda.Start(Handler)
}
要与标准库一起使用,该函数接收一个 http.Handler
对象(其中定义了路由),并返回一个 httpadapter.HandlerAdapter
对象。然后,可以使用 ProxyWithContext
方法将其作为Lambda处理程序。
部署到AWS Lambda
使用SAM CLI将这些函数部署到AWS Lambda。
先决条件
需要安装了Go编程语言(v1.18或更高版本)和AWS SAM。克隆项目并切换到正确的目录。
git clone https://github.com/build-on-aws/golang-apis-on-aws-lambda
cd golang-apis-on-aws-lambda
基于gorilla和mux的Lambda函数
首先,将CodeUri
在template.yaml
文件中更新为代码所在的本地文件夹路径。 构建函数:
sam build
#expected output
Building codeuri: <path>/lambda-go-api-proxy-getting-started/gorilla runtime: go1.x metadata: {} architecture: x86_64 functions: DemoFunction
Running GoModulesBuilder:Build
Build Succeeded
....
部署函数(按照SAM CLI的提示进行操作):
export STACK_NAME=lambda-go-gorilla
sam deploy --stack-name $STACK_NAME --guided
# response to the prompts
Stack Name [lambda-go-gorilla]: <press enter>
AWS Region [us-east-1]: <enter alternate region or press enter>
#Shows you resources changes to be deployed and require a 'Y' to initiate deploy
Confirm changes before deploy [y/N]: n
#SAM needs permission to be able to create roles to connect to the resources in your template
Allow SAM CLI IAM role creation [Y/n]: y
#Preserves the state of previously provisioned resources when an operation fails
Disable rollback [y/N]: n
DemoFunction may not have authorization defined, Is this okay? [y/N]: y
Save arguments to configuration file [Y/n]: y
SAM configuration file [samconfig.toml]: <press enter>
SAM configuration environment [default]: <press enter>
部署完成后,转到AWS控制台,检查已部署的堆栈和相关资源。这些资源包括Lambda函数、API Gateway(REST API)、IAM角色等。
可以在SAM CLI的输出中看到API Gateway的端点,或者在Outputs部分中找到它。
-----------------------------------------------------------------------------------------------------
CloudFormation outputs from deployed stack
--------------------------------------------------------------------------------------------------------
Outputs
--------------------------------------------------------------------------------------------------------
Key APIGWEndpoint
Description API Gateway Endpoint
Value https://whrd2yy3ug.execute-api.us-east-1.amazonaws.com/dev/ping
--------------------------------------------------------------------------------------------------------
Successfully created/updated stack - lambda-go-gorilla in us-east-1
要测试函数,请使用以下命令调用API Gateway:
export API_ENDPOINT=<enter the API Gateway endpoint here>
curl $API_ENDPOINT
会得到类似以下的响应:
{
"from": "gorilla",
"message": "Tue Jun 27 18:10:54 UTC 2023"
}
net/http和基于echo的Lambda函数
在部署这两个函数之前,请确保将CodeUri
更新为代码所在的本地文件夹路径:- 对于net/http
包,更新为http-stdlib/
。- 对于echo
框架,更新为echo/
。构建并部署函数(按照之前的提示进行操作):
sam build
# change the stack name to lambda-go-echo in case of "echo" framework
export STACK_NAME=lambda-go-nethttp
sam deploy --stack-name $STACK_NAME --guided
可以通过调用API Gateway端点来测试函数:
export API_ENDPOINT=<enter your API endpoint here>
curl $API_ENDPOINT
会得到下面的响应:
{
"from": "net/http",
"message": "Tue Jun 27 18:20:42 UTC 2023"
}
对于框架的情况,会得到下面的响应(注意字段中的不同名称):
{
"from": "echo",
"message": "Tue Jun 27 18:30:25 UTC 2023"
}
以上步骤已成功将Go API部署为AWS Lambda函数。完成后,请删除堆栈:
sam delete --stack-name lambda-go-gorilla
sam delete --stack-name lambda-go-nethttp
sam delete --stack-name lambda-go-echo
结论
上面演示了AWS Lambda Go API代理,以及它的框架/包(对于gorilla/mux、echo和net/http)特定的适配器实现,能够将现有的Go应用程序作为AWS Lambda函数运行,并由API Gateway提供前端服务。通过简单的代码示例学习了基本概念,使用AWS SAM CLI部署了这些函数,并通过调用API Gateway端点进行了验证。
作者:Abhishek Gupta
更多技术干货请关注公众号“云原生数据库”
squids.cn,目前可体验全网zui低价RDS,免费的迁移工具DBMotion、SQL开发工具等。