GIN 101: สร้าง Web Service บน Golang

Piirapol Pajharawat
InsightEra
Published in
3 min readDec 31, 2019
Photo by Jason Wong on Unsplash

What is Gin?

Gin เป็น web framework ที่เขียนด้วยภาษา golang ที่ถูกพัฒนาต่อมาจาก Martini ที่หยุดพัฒนาไปแล้ว โดย Gin จะใช้ customized httprouter ทำให้มีประสิทธิภาพด้านความเร็วที่สูงมาก ถ้าคุณกำลังมองหา framework ที่มี performance กับ productivity ที่ดี Gin เป็นหนึ่งในตัวเลือกที่น่าสนใจเลยทีเดียว

https://github.com/gin-gonic/gin

Installation

ก่อนติดตั้ง Gin จะต้อง install Go และ Go workspace ก่อนนะครับ สำหรับคนที่ยังไม่ได้ติดตั้ง ลองเข้าไปอ่านบทความนี้ดูก่อนนะครับ สำหรับคนที่มีแล้ว ลองเช็คดูว่า Go version ใหม่กว่า 1.11 หรือเปล่า ถ้าเก่ากว่าต้องอัพเดท version ด้วยนะครับ ไม่อย่างนั้นจะใช้ไม่ได้

$ go get -u github.com/gin-gonic/gin

ใช้งานโดย import เข้าไปใน go file

import "github.com/gin-gonic/gin"

Quick Start

เมื่อ install เสร็จแล้ว เรามาลองใช้กันเลย!

ใน code ตัวอย่างนี้จะเป็นการสร้าง path /ping ซึ่งเป็น method GET โดยจะ response กลับมาเป็น json ที่มีข้อความ {“message”: “pong”} หากเรียกสำเร็จ

ทีนี้เรามาลอง run กันครับ

$ go run example.go

หลังจาก program start เสร็จแล้ว ถ้าเข้าไปที่ localhost:8080/ping ผ่าน web browser ก็จะเจอกับ result หน้าตาแบบนี้

การใช้งาน API

ใน repository ของ Gin มีตัวอย่างที่พร้อมให้ลองใช้งานอยู่ที่ Gin examples repository ลองเข้าไปดูได้ครับ

Gin สามารถตั้ง method ของแต่ละ route ได้ตามที่เราต้องการใช้เลยครับ

เราสามารถเลือก port ที่ต้องการรัน server ได้ด้วยการใส่เลข port เข้าไปเป็น parameter ของ router.Run()

Handler Function & Query

Gin จะใช้ handler function ในการทำ operation ต่างๆ โดยทั่วไปจะใช้ *gin.Context เป็น Context ในการรับส่งค่าต่างๆ

จากในตัวอย่างผมดึง handler function ออกมาเป็น function แยกเพื่อทำให้การเขียน code สะดวกมากขึ้น (เพราะถ้าเขียนทุกอย่างใน main สุดท้ายมันจะรกมากๆ)

Gin สามารถรองรับการ query ข้อมูลจาก request ได้ค่อนข้างหลากหลาย ในตัวอย่างนี้ผมได้เลือก query ที่ผมใช้บ่อยๆ มาใส่ไว้ครับ โดยผมจะลองทดสอบ API โดยใช้ Insomnia ในการยิง request

สำหรับ function exampleFunc จะเห็นได้ว่า เราเรียกใช้การดึงข้อมูลสองรูปแบบคือ c.Query และ c.PostForm

  • c.Query จะเป็นการดึงข้อมูลจาก parameter ของ request โดยใช้ชื่อ key (ในที่นี้ก็คือส่วนของ id ซึ่งอยู่ต่อจาก url
  • c.PostForm จะเป็นการดึงข้อมูลจาก Multipart หรือ Urlencoded Form ด้วย key เช่นกัน

สำหรับ function exampleJSON จะเป็นการ bind ข้อมูลมาเก็บไว้ใน structure โดยใช้คำสั่ง c.BindJSON ซึ่งคำสั่งนี้จะทำงานคล้ายๆ กับการ Unmarshal เพียงแต่ใช้ input จาก request แทนการใช้ตัวแปร แต่การใช้ c.BindJSON นั้นจะสามารถทำได้ครั้งเดียว นั่นหมายความว่า หาก bind ไปแล้วข้อมูลส่วนนั้นใน request จะหายไปเลย ไม่สามารถ bind ซ้ำได้อีก

Middleware

Middleware จะเป็นส่วนที่ค่อนข้างมีความสำคัญมากในการสร้าง web service ด้วย Gin ซึ่งจะมีบทบาทหลักในการทำ authentication และ custom logging หรือถ้าหากเราต้องการให้มี function กลางที่ต้องทำก่อนใช้ API โดยจะมีรูปแบบการใช้งานดังนี้

result:

ora
[GIN] 2019/12/24 - 18:27:34 |200|0s|::1|POST /user/test?id=1234
ora
muda
[GIN] 2019/12/24 - 18:27:42 |200|0s|::1|POST /admin/test

Middleware function จะ return gin.HandlerFunc หรือก็คือ function รูปแบบเดียวกับที่เราทำไปก่อนหน้านี้นั่นเอง คำสั่ง r.Use จะเป็นการประกาศว่าทุกๆ route ที่อยู่ใต้บรรทัดนี้จะต้องผ่านการ execute จากบรรทัดนี้ก่อนเท่านั้น

Group

การแบ่งกลุ่มพูดง่ายๆ ก็คือการแยก parent path นั่นเองครับ การใช้ group จะมีประโยชน์คือใช้ในการแบ่ง API ออกเป็นกลุ่มๆ ทำให้ง่ายต่อการใช้งาน และยังสามารถสร้าง middleware มาครอบเฉพาะกลุ่มได้ด้วย ตัวอย่างเช่น

ถ้าเรายิงไปที่ path /user/test ระบบจะผ่านแค่ function exampleMiddleware ก่อนที่จะเริ่มทำในส่วนที่เป็น API แต่ถ้ายิงไปที่ /admin/test ระบบจะผ่าน exampleMiddleware และ authenticationMiddleware ก่อนจึงจะทำในส่วน API

gin.Context

จริงๆแล้วเจ้าตัว c หรือ *gin.Context นั้นมีอะไรให้เราเลือกใช้ได้มากกว่าการ query หรือ ทำ JSON response โดยเฉพาะใน API ที่ต้องการ middleware ยกตัวอย่างเช่น บางทีเราอาจจะต้อง bindJSON ใน middleware แต่ก็ต้องการใช้ json นั้นใน API ด้วย หรือ เราอาจจะอยากทำ custom log ที่ต้องการเก็บข้อมูลทั้งก่อนและหลัง API process ตัว context ของ Gin รองรับ procedure พวกนี้ทั้งหมด โดยผมจะยกตัวอย่างตัวที่ผมได้มีโอกาสใช้บ่อยๆ ให้ดูครับ (สามารถดู context command ทั้งหมดได้ ที่นี่ ครับ)

ในตัวอย่างจะมี command ตามนี้ครับ

  • c.Set() จะเป็นการ set key และ value เข้าไปใน context เพื่อทำให้สามารถนำค่านั้นไปใช้ที่อื่นที่ c ไปถึงได้ (เช่น middleware กับ API function)
  • c.Get() เป็นการ get ข้อมูลที่ได้มีการ set ไว้ก่อนแล้วด้วย key โดยที่ function จะ return value ที่ set ไว้พร้อมกับ boolean 1 ตัวที่บอกว่า key นั้น exist หรือเปล่า
  • c.Next() คือการสั่งให้ระบบข้ามไปทำใน function ต่อไป (อาจจะเป็น middleware อีกตัวหรือส่วน API เลยก็ได้) แล้วจึงกลับมาทำส่วน middleware ต่อหลังจาก API process เสร็จสิ้น
  • c.Abort() คือสั่งให้ process จบ ณ ตรงนั้น

result:

testFunc
[GIN] 2019/12/24 - 17:40:57 | 200 | 889.7906ms | ::1 | POST /test

จริงๆ แล้วยังมี c.Request ที่สามารถดึงข้อมูลของ request (เช่น header, host, method) ได้อีกด้วย แต่เนื้อหาส่วนนั้นค่อนข้างกว้างจึงไม่ได้ใส่มาในบทความนี้ครับ

Conclusion

ก็จบไปแล้วกับ Gin 101 ครับ ผมรู้สึกว่าสำหรับผมแล้ว ผมใช้เวลากับการศึกษา middleware ค่อนข้างนานกว่าจะใช้ได้คล่องจึงอยากมาแชร์ส่วนนี้ก่อนโดยที่ยังไม่ได้พูดถึงเกี่ยวกับการคุยกับ database (จริงๆ ยังเลือกไม่ถูกว่าจะพูดถึงตัวไหนดี) เพราะส่วนตัวผมใช้คู่กับ httpRequest ด้วยการจับเวลาใน middleware เลยช่วยได้เยอะครับ ส่วนตัวจากที่ใช้ Gin มารู้สึกว่ามันอาจจะไม่ได้ใช้ง่ายเหมือน Node ที่เป็น javascript แต่เรื่องประสิทธิภาพและความเร็วถือว่าเหนือกว่าค่อนข้างเยอะเลยครับยังไงก็ขอฝาก Gin ไว้เป็นตัวเลือกสำหรับคนที่ต้องการ web service ที่มี performance กับ productivity ที่ดีด้วยนะครับ

References

--

--