使用AWS Lambda在Go中构建RESTful API
在本文中,我們將學習使用AWS Lambda在Go中設計,構建和部署RESTful API。 在開始之前,讓我給您簡要介紹一下AWS Lambda。
什么是AWS Lambda?
AWS Lambda是一種無服務器計算服務,可運行我們的代碼以響應事件并自動為我們管理基礎計算資源。 我們可以使用AWS Lambda通過自定義邏輯擴展其他AWS服務,或者創建我們自己的后端服務,這些后端服務以AWS規模,性能和安全性運行。 AWS Lambda可以自動運行代碼以響應多個事件,例如通過Amazon API Gateway發出的HTTP請求,對Amazon S3存儲桶中的對象的修改,Amazon DynamoDB中的表更新以及AWS Step Functions中的狀態轉換。
Lambda在高可用性計算基礎架構上運行我們的代碼,并執行所有計算資源管理,包括服務器和操作系統維護,容量配置和自動縮放,代碼和安全補丁部署以及代碼監視和日志記錄。 我們需要做的就是提供代碼。
現在,讓我們開始構建一個API,該API將幫助本地電影租賃店管理其可用電影。
API架構
下圖顯示了API Gateway和Lambda如何適應API體系結構:
AWS Lambda支持微服務開發。 話雖如此,每個端點都會觸發不同的Lambda函數。 這些功能彼此獨立并且可以用不同的語言編寫,從而導致在功能級別上進行縮放,更易于進行單元測試以及松散耦合。
來自客戶端的所有請求都首先通過API網關。 然后,它將傳入的請求相應地路由到正確的Lambda函數。
請注意,單個Lambda函數可以處理多種HTTP方法( GET , POST , PUT , DELETE等)。 建議為每個功能創建多個Lambda函數,以利用微服務的功能。 但是,構建單個Lambda函數來處理多個端點可能是一個不錯的練習。
端點設計
現在已經定義了體系結構,是時候完成上圖中描述的功能的實現了。 您可以使用net / http Go包并使用內置的狀態代碼變量,例如http.StatusOK , http.StatusCreated , http.StatusBadRequest , http.StatusInternalServerError等 ,而不是對HTTP狀態代碼進行硬編碼。
GET方法
要實現的第一個功能是列出電影。 這就是GET方法起作用的地方。 讓我們從以下步驟開始:
步驟1:創建注冊了findAll處理程序的Lambda函數。 該處理程序將電影列表轉換為字符串,然后返回由APIGatewayProxyResponse變量包裝的字符串以及200 HTTP狀態代碼。 如果轉換失敗,它也會處理錯誤。 處理程序的實現如下:
package mainimport ("encoding/json""github.com/aws/aws-lambda-go/events""github.com/aws/aws-lambda-go/lambda" )var movies = []struct {ID int `json:"id"`Name string `json:"name"` }{{ID: 1,Name: "Avengers",},{ID: 2,Name: "Ant-Man",},{ID: 3,Name: "Thor",},{ID: 4,Name: "Hulk",}, {ID: 5,Name: "Doctor Strange",}, }func findAll() (events.APIGatewayProxyResponse, error) {response, err := json.Marshal(movies)if err != nil {return events.APIGatewayProxyResponse{}, err}return events.APIGatewayProxyResponse{StatusCode: 200,Headers: map[string]string{"Content-Type": "application/json",},Body: string(response),}, nil }func main() {lambda.Start(findAll) }您可以使用net / http Go包并使用內置的狀態代碼變量,例如http.StatusOK , http.StatusCreated , http.StatusBadRequest , http.StatusInternalServerError等 ,而不是對HTTP狀態代碼進行硬編碼。
步驟2:創建一個包含以下內容的腳本文件,以構建Lambda函數部署包,一個包含您的代碼和任何依賴項的.zip文件,如下所示:
#!/bin/bashecho "Build the binary" GOOS=linux GOARCH=amd64 go build -o main main.goecho "Create a ZIP file" zip deployment.zip mainecho "Cleaning up" rm main步驟3:執行以下命令以將部署包構建為.zip文件:
$ chmod +x build.sh $ ./build.sh步驟4:使用此處提到的步驟配置AWS CLI。 配置完成后,按照此處提到的步驟創建一個名稱為FindAllMoviesRole的AWS角色,并驗證是否成功創建該角色:
$ aws iam get-role --role-name FindAllMoviesRole上面的命令應給出響應,如下面的屏幕快照所示:
步驟5:接下來,使用AWS CLI創建一個新的Lambda函數,如下所示:
aws lambda create-function --function-name FindAllMovies \--zip-file fileb://deployment.zip \--runtime go1.x --handler main \--role arn:aws:iam::ACCOUNT_ID:role/FindAllMoviesRole \--region us-east-1創建函數后,將為我們提供與以下屏幕快照所示的輸出相同的輸出:
步驟6 :回到AWS Lambda控制臺,您應該看到該函數已成功創建:
步驟7 :創建一個帶有空JSON的示例事件,因為該函數不需要任何參數,然后單擊Test按鈕:
您將在上一個屏幕截圖中注意到,該函數以JSON格式返回預期的輸出。
步驟8:現在已經定義了函數,您需要創建一個新的API網關來觸發它:
步驟9:接下來,從“ 操作”下拉列表中,選擇“ 創建資源并將其命名為電影” :
步驟10:通過點擊Create Method在此/ movies資源上公開GET 方法 。 在“ 集成類型”部分下選擇“ Lambda函數 ”,然后選擇“ FindAllMovies”函數:
步驟11:要部署API,請從“ 操作”下拉列表中選擇“ 部署API ”。 系統將提示您創建一個新的部署階段:
步驟12:一旦創建了部署階段,就會顯示一個調用URL:
步驟13:將瀏覽器指向給定的URL或使用現代的REST客戶端(例如Postman或Insomnia)。 您可以使用cURL工具,因為默認情況下它已安裝在幾乎所有操作系統上:
curl -sX GET https://51cxzthvma.execute-api.us-east-1.amazonaws.com/staging/movies | jq '.'上面的命令將以JSON格式返回電影列表:
調用GET端點時,請求將通過API網關,這將觸發findAll處理程序。 這會將API網關代理的響應以JSON格式返回給客戶端。
現在已經部署了findAll函數,您可以實現findOne函數以通過其ID搜索電影。
帶參數的GET方法
findOne處理程序需要包含事件輸入的APIGatewayProxyRequest參數。 然后,它使用PathParameters方法獲取影片ID并對其進行驗證。
如果提供的ID無效,則Atoi方法將返回錯誤,并將500錯誤代碼返回給客戶端。 否則,將根據索引獲取電影,并以包裝在APIGatewayProxyResponse中的200 OK狀態返回給客戶端:
...func findOne(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {id, err := strconv.Atoi(req.PathParameters["id"])if err != nil {return events.APIGatewayProxyResponse{StatusCode: 500,Body:?????? "ID must be a number",}, nil}response, err := json.Marshal(movies[id-1])if err != nil {return events.APIGatewayProxyResponse{StatusCode: 500,Body:?????? err.Error(),}, nil}return events.APIGatewayProxyResponse{StatusCode: 200,Headers: map[string]string{"Content-Type": "application/json",},Body: string(response),}, nil}func main() {lambda.Start(findOne)}與FindAllMovies函數類似,創建一個新的Lambda函數以搜索電影:
aws lambda create-function --function-name FindOneMovie \--zip-file fileb://deployment.zip \--runtime go1.x --handler main \--role arn:aws:iam::ACCOUNT_ID:role/FindOneMovieRole \--region us-east-1返回API Gateway控制臺,創建一個新資源,公開GET方法,然后將資源鏈接到FindOneMovie函數。 注意在路徑中使用{id}占位符。 id的值將通過APIGatewayProxyResponse對象提供。 以下屏幕截圖描述了這一點:
重新部署API,并使用以下cURL命令測試端點:
curl -sX https://51cxzthvma.execute-api.us-east-1.amazonaws.com/staging/movies/1 | jq '.'將返回以下JSON:
使用ID調用API URL時,如果存在ID對應的影片,則返回該影片。
POST方法
現在,您知道帶有和不帶有路徑參數的GET方法如何工作。 下一步是通過API網關將JSON有效負載傳遞給Lambda函數。 該代碼是不言自明的。 它將輸入的請求轉換為電影結構,將其添加到電影列表,然后以JSON格式返回新的電影列表:
package mainimport ("encoding/json""strconv""github.com/aws/aws-lambda-go/events""github.com/aws/aws-lambda-go/lambda" )type Movie struct {ID int `json:"id"`Name string `json:"name"` }var movies = []Movie{Movie{ID: 1,Name: "Avengers",},... }func insert(req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {var movie Movieerr := json.Unmarshal([]byte(req.Body), &movie)if err != nil {return events.APIGatewayProxyResponse{StatusCode: 400,Body: "Invalid payload",}, nil}movies = append(movies, movie)response, err := json.Marshal(movies)if err != nil {return events.APIGatewayProxyResponse{StatusCode: 500,Body: err.Error(),}, nil}return events.APIGatewayProxyResponse{StatusCode: 200,Headers: map[string]string{"Content-Type": "application/json",},Body: string(response),}, nil }func main() {lambda.Start(insert) }接下來,使用以下命令為InsertMovie創建一個新的Lambda函數:
aws lambda create-function --function-name InsertMovie \--zip-file fileb://deployment.zip \--runtime go1.x --handler main \--role arn:aws:iam::ACCOUNT_ID:role/InsertMovieRole \--region us-east-1接下來,在/ movies資源上創建一個POST方法,并將其鏈接到InsertMovie函數:
要對其進行測試,請使用下面的cURL命令以及POST動詞和-d標志,后跟JSON字符串(具有id和name屬性):
curl -sX POST -d '{"id":6, "name": "Spiderman:Homecoming"}' https://51cxzthvma.execute-api.us-east-1.amazonaws.com/staging/movies | jq '.'上面的命令將返回以下JSON響應:
如您所見,新電影已成功插入。 如果再次測試,它應該可以按預期工作:
curl -sX POST -d '{"id":7, "name": "Iron man"}' https://51cxzthvma.execute-api.us-east-1.amazonaws.com/staging/movies | jq '.'前面的命令將返回以下JSON響應:
如您所見,它成功完成并且再次按預期方式插入了影片,但是如果您等待幾分鐘并嘗試插入第三部影片怎么辦? 以下命令將用于再次執行它:
curl -sX POST -d '{"id":8, "name": "Captain America"}' https://51cxzthvma.execute-api.us-east-1.amazonaws.com/staging/movies | jq '.'再次,將返回一個新的JSON響應:
您會發現ID為6和7的電影已被刪除; 為什么會這樣? 這很簡單。 Lambda函數是無狀態的。
首次(首次插入)調用InsertMovie函數時,AWS Lambda將創建一個容器并將函數有效負載部署到該容器。 然后,它保持活動狀態幾分鐘,然后終止( 熱啟動 ),這說明了第二個刀片通過的原因。 在第三個插件中,該容器已經終止,因此Lambda創建一個新容器( 冷啟動 )以處理該插件。
這就是為什么以前的狀態會丟失的原因。 下圖說明了冷/熱啟動問題:
這就解釋了為什么Lambda函數應該是無狀態的,為什么您不應該做出任何假設將狀態從一次調用保留到另一次調用的假設。
完整的源代碼托管在github上 。
翻譯自: https://www.javacodegeeks.com/2018/11/build-restful-api-go-using-aws-lambda.html
總結
以上是生活随笔為你收集整理的使用AWS Lambda在Go中构建RESTful API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: jaxb 映射 空字段_推土机:将JAX
- 下一篇: 苹果发布 iPadOS 17 正式版:引