SOFTWARE DEVELOPMENT | 10 mins read

ทำ REST APIs บน AWS Lambda ด้วย Go

By Ball on 11 Jan 2021
sennalabs-blog-banner

สวัสดีครับผู้อ่านทุกท่าน วันนี้ผมจะพาทุกคนมาทำ 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 แล้วพบกันบทความหน้าครับ

Written By