ทำ REST APIs บน AWS Lambda ด้วย Go
สวัสดีครับผู้อ่านทุกท่าน วันนี้ผมจะพาทุกคนมาทำ Rest API แบบง่าย ๆ บน Lambda กันครับ ซึ่งถ้าใครยังไม่รู้จักเจ้า Lambda ผมได้เขียนบทความรวมถึงตัวอย่างการใช้ Lambda ที่ไม่ใช่การทำ REST APIs ไว้ด้วย สามารถเข้าไปดูได้ที่ จัดการทุก request ของ AWS แบบง่ายด้วย Lambda function
สิ่งที่เราจะใช้นั้น ได้แก่
- Gin เป็น Framework ตัวหนึ่งที่ใช้ในการทำ API ของ Golang ซึ่งเป็นที่นิยมมาก
- AWS Lambda ใช้ในการรันโค้ดของเรา
- AWS API Gateway ใช้ในการเรียก Lambda ผ่าน HTTP เนื่องจาก Lambda นั้นไม่สามารถเรียกผ่าน HTTP ได้โดยตรง จึงต้องใช้เจ้า API Gateway มาเรียกใช้ Lambda อีกที
โดยมีโครงสร้างการทำงาน ดังรูปนี้
เริ่มลงมือทำ Rest API
เริ่มจากสร้าง directory project กันก่อน
$ mkdir $GOPATH/src/go-lambda-api-example$ cd $GOPATH/src/go-lambda-api-example$ go mod init$ touch main.go
ส่วนโค้ดที่ใช้ทดสอบของผม ใช้ตามด้านล่างนี้
// main.go
package main
import "github.com/gin-gonic/gin"
type user struct { Name string `json:"name"` Age int `json:"age"`}
func main() { app := gin.Default() app.GET("/hello", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "hello world", }) }) app.POST("/user", func(c *gin.Context) { var u user if err := c.ShouldBindJSON(&u); err != nil { c.JSON(400, gin.H{"message": err.Error()}) return } c.JSON(200, u) }) app.Run(":3000")}
จากนั้นทดสอบว่ารันสำเร็จหรือไม่ โดยเริ่มรันเซิร์ฟเวอร์ก่อน
$ go run main.go
ลองตรวจสอบ Request และ Response กันหน่อย
เมื่อใช้ได้ตามต้องการแล้ว เรามา Modify เพิ่มอีกนิดเพื่อให้ใช้บน Lambda และสามารถรันบน Local ได้
package main
import ( "context" "github.com/aws/aws-lambda-go/events" "github.com/aws/aws-lambda-go/lambda" ginadapter "github.com/awslabs/aws-lambda-go-api-proxy/gin" "github.com/gin-gonic/gin")
type user struct { Name string `json:"name"` Age int `json:"age"`}
var ginLambda *ginadapter.GinLambda
func lambdaHandler(ctx context.Context, req events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { if ginLambda == nil { ginLambda = ginadapter.New(ginEngine()) } return ginLambda.ProxyWithContext(ctx, req)}
func ginEngine() *gin.Engine { app := gin.Default() app.GET("/hello", func(c *gin.Context) { c.JSON(200, gin.H{ "message": "hello world", }) }) app.POST("/user", func(c *gin.Context) { var u user if err := c.ShouldBindJSON(&u); err != nil { c.JSON(400, gin.H{"message": err.Error()}) return } c.JSON(200, u) }) return app}
func main() { if gin.Mode() == "release" { lambda.Start(lambdaHandler) } else { app := ginEngine() app.Run(":3000") }}
อธิบายโค้ดด้านบนสักนิด สิ่งที่เพิ่มมาอย่างแรกเลย คือ package aws-lambda-go-api-proxy ซึ่งเป็นตัวจัดการ request proxy ของ Api Gateway แล้วส่งมาให้ Lambda จากนั้นก็จะแยกโค้ด Instance ของ Gin มาไว้ใน ginEngine() เพื่อแยกการทำงานระหว่าง Lambda กับ Local โดยใช้ Mode ของ Gin
เมื่อเสร็จเรียบร้อยแล้วเราต้องทำการ build เจ้าตัว project ให้เป็น execution file เพื่อนำไปใช้บน Lambda แล้วก็ซิปไฟล์ที่ build เป็น .zip ด้วยนะครับ
$ GOOS=linux go build -o main .
สร้าง Lambda function กันต่อ
เริ่มจากไปที่ AWS Management Console ไปที่ Lambda แล้วคลิก create function บริเวณมุมขวาบน จากนั้นกรอกข้อมูล Function name ตามใจผู้อ่านและเลือก Runtime เป็น Go ตามภาพ แล้วกด create function ได้เลย
เมื่อสร้างแล้วเลื่อนลงมาที่ Function code กด Actions > Upload a .zip file แล้วเลือกไฟล์ที่เราซิปไว้ หลังจากนั้นไปตรง Runtime setting ให้ Edit Handler จาก hello เป็น main
จากนั้นไปที่ Environment variable แล้วเพิ่ม GIN_MODE เป็น release เพื่อให้ Gin รันในโหมด production และเรียกใช้ lambda handler ที่เราเขียนเงื่อนไขไว้ใน main() (ถ้ามี env อื่น ๆ ก็สามารถเพิ่มได้ตามต้องการ)
เลื่อนมาต่อที่ Basic settings ซึ่งผู้อ่านสามารถแก้ไข Memory และเวลา Timeout ของ function ได้ ซึ่งผมจะแก้ Memory เป็น 128mb ตามภาพ เนื่องจากตัว example นี้ไม่ได้ใช้ memory อะไรมากมาย ผู้อ่านสามารถปรับได้ตามความเหมาะสม
เป็นอันเสร็จเรียบร้อยกับการ Setup Lambda แต่ยังใช้ไม่ได้นะครับ เพราะยังเหลืออีกหนึ่งขั้นตอนที่สำคัญ คือ การสร้าง API Gateway
การสร้าง API Gateway เพื่อเรียกใช้ Lambda
เข้าไปที่ AWS Management Console > API Gateway แล้ว Create API ทางขวาบนเช่นเดิม จากนั้นกด Build ที่หัวข้อ REST API แล้วกรอก API name ตามใจผู้อ่านได้เลย เสร็จแล้วก็กด Create API
จากนั้นกดที่ Actions > Create Resource
ทำเครื่องหมายถูกที่ proxy resource ตามภาพ ซึ่งส่วนที่เป็น Resource Name และ Resource Path จะถูกใส่ให้อัตโนมัติ แต่ถ้าระบบไม่กรอกให้ สามารถกรอกตามภาพได้เลยครับ เสร็จแล้วกด Create Resource
จากนั้นเลือก Lambda function โดย search จากชื่อเราตั้งไว้ แล้วกด Save
ไปที่ Actions > Deploy API เลือก Deployment stage เลือก [New Stage] กรอก Stage name แล้วกด Deploy ได้เลย (กรณีที่มีการแก้ไข Resource หรือ Method ต่าง ๆ สามารถ Deploy ที่ Deployment stage เดิมที่สร้างไว้ได้เลย)
จากนั้นจะได้ Url มา ซึ่งเราสามารถ Copy แล้วนำไปใช้ได้เลย
ทดสอบผลลัพธ์กันหน่อย
ก็จบไปแล้วนะครับกับแนวทางการทำ REST APIs บน AWS Lambda ถ้าหากผิดพลาดประการใดขออภัยผู้อ่านด้วยนะครับ ลองเข้าไปดูโค้ดตัวอย่างได้ที่ Go Lambda API example แล้วพบกันบทความหน้าครับ