มาทำ HTTP/Rest Endpoint ไปยัง gRPC service ด้วย Go กัน

Teerasak N
THE EXISTING COMPANY
4 min readFeb 14, 2020

มาทำความเข้าใจในส่วน gRPC กันก่อน

เนื่องจาก gRPC service นั้นจะทำการสื่อสารบน HTTP 2 แต่ ทาง API Client นั้นจะเป็น HTTP 1 เท่านั้น ส่ิงที่จะทำให้ฝั่ง API Client กับ gRPC Service สื่อสารกันได้ ก็คือตัวกลาง หรือในบทความนี้จะใช้ grpc-gateway ในการทำ proxy ให้ฝั่ง API Client สามารถสื่อสารมายัง gRPC service ได้

  • โครงสร้างการทำงานเป็นดังนี้
https://github.com/grpc-ecosystem/grpc-gateway

สามารถอ่าน documentation ได้ที่ grpc-gateway

สามารถดูโค้ดตัวอย่างก่อนเร่ิมต้นได้ที่นี้

ก่อนที่เราจะเริ่มต้น เราจำเป็นต้องสร้างโครงสร้างโครงการ Go

โดยเราจะใช้ template for Go project:

มาลุยกันเลย

ขั้นแรกให้สร้างโปรเจคเราไว้ที่ root project

mkdir patstore-service
cd patstore-service
go mod init github.com/<you>/patstore-service

สร้างโฟลเดอร์ไว้เก็บ API definition:

mkdir -p api/proto/v1

โดยที่ v1 คือเวอร์ชัน API

API versioning: เป็นวิธีปฏิบัติที่ดีในการค้นหา API เวอร์ชันหลักในโฟลเดอร์ต่างๆ

ต่อไปสร้าง petstore-service.proto ไว้ใน api\proto\v1 :

https://gist.github.com/teerasaknrt/468925817c70623756e22a758ac2d589

สามารถไปศึกษาสเปคของภาษา proto เพิ่มเติมได้ที่ :

การที่เราจะ Compile Proto เราจำเป็นต้องติดตั้งเครื่องมือที่จำเป็นและเพิ่มแพ็คเกจ

  • สามารถไปดาวน์โหลดไลบรารี่ของตัวคอมไพเลอร์ได้ที่ :
  • ติดตั้งไว้ที่ “bin” ของ env ของเครื่อง
  • สร้างโฟลเดอร์ที่ชื่อว่า trird_party
  • เลือกมาจาก “bin” ที่เราติดตั้งก่อนหน้านี้แล้ว copy เฉพาะตัวที่ต้องการใช้งาน
  • เราจำเป็นต้องติดตั้ง Plugin ของภาษา Go เพื่อใช้งาน protoc compiler:
go get -u github.com/golang/protobuf/protoc-gen-go
  • สร้าง protoc-gen.cmd (protoc-gen.sh for MacOS/Linux) ไว้ในโฟลเดอร์ “third_party” :
https://gist.github.com/teerasaknrt/32af4121d743e537d865bc430aa91275
  • สร้าง forder เพื่อรองรับการ gen-protoc
mkdir -p api/swagger
mkdir -p pkg/api/v1
  • แล้วลอง run proto compiler ด้วยคำสั่งนี้:
./third_party/protoc-gen.sh

ต่อไปจะเป็นการพัฒนาแพคแกจของเรากัน

  • เริ่มจากการสร้างโฟลเดอร์ pkg/service เพื่อสร้าง
mkdir -p pkg/service && cd pkg/service 
  • แล้วก็ลงมือเขียนโค้ดตามนี้ครับ:
https://gist.github.com/0fdc3a1021c7dfe8620f9edd34255bb5.git
  • โดยในแพคแกจนี้จะใช้ database ของ firestore ลองไปศึกษาเพิ่มเติมได้ที่:
  • ต่อไปนี้เราจะมาสร้างโปรโตคอลเพื่อให้ฝั่ง client และ server สื่อสารกันได้ สร้างไว้อยู่ภายใต้ pkg
  • ก่อนอื่นสร้างโฟลเดอร์ config ไว้สำหรับใส่ค่า config ทั้งหมดของ pkg ไว้ที่ภายใต้ petstore-service
mkdir config
cd config
  • ทำการสร้างไฟล์ config.go
https://gist.github.com/teerasaknrt/68a29ea2c43c075b82a097a7a813a012
  • และทำการสร้าง local-config.yaml เพื่อจะใส่ key กับ value ที่เราต้องการเปลี่ยนค่าคอนฟิกได้ ในส่วนนี้จะเขียนให้ดูแค่ local-config.ymal แต่ถ้ามี env อื่นก็สร้างสามารถสร้างไฟล์เพิ่มได้ตาม env ที่ต้องการ
https://gist.github.com/teerasaknrt/526d50be232cb0c01e33ef656923fdd1
  • เรามาเริ่มทำฝั่ง gRPC กันก่อน
mkdir -p protocol/grpc && cd protocol/grpc

ทำการสร้างไฟล์ server.go

https://gist.github.com/teerasaknrt/d6ec1e7833072888828b19d4c3091849
  • ต่อไปก็มาทำฝั่ง REST ต่อ
cd ..
mkdir rest && cd rest

แล้วก็สร้างไฟล์ที่ชื่อว่า server.go เหมือนฝั่ง gRPC เลยแต่โค้ดจะต่างกันเพราะไฟล์นี้เราจะใช้ให้ HTTP คุยกับทาง gRPC ได้

https://gist.github.com/teerasaknrt/7418701c550e093ebf4b7736f7eb74e7

เพียงเท่านี้เราก็จะได้ Protocol ไว้ให้ฝั่ง HTTP คุยกับ gRPC ได้แล้ว

  • ต่อมาเราก็มาสร้างโฟลเดอร์ cmd จะอยู่ภายใต้ pkg
mkdir cmd && cd cmd
  • แล้วเราก็สร้างไฟล์ที่ชื่อว่า server.go เพื่อทำการ run โปรโตคอลทั้งสองฝั่งของ server ที่เราสร้างไว้ก่อนก่อนโดยเขียนดังนี้
https://gist.github.com/teerasaknrt/d268288bb2d2c4193a4bc711ca1a62b2
  • สุดท้ายเรามาสร้างไฟล์สำหรับการ run ทั้งหมดของ pkg ไว้ที่ภายใต้ petstore-service
mkdir -p cmd/server && cd cmd/server
https://gist.github.com/teerasaknrt/bc113bf8815e6c54c66bc74ba2789c2b

ลองไปทดสอบกันเลย 🤹‍♂️

go run cmd/server/main.go -env=local

ทดสอบด้วยการยิง API ด้วย Postman

สรุป

ทำไมเราถึงมาใช้ gRPC มาดูข้อดีกันครับ

  • gRPC ใช้ “Protobuf”, “HTTP/2” และ “Google” พัฒนา
  • รองรับทั้งการเขียนแบบ synchronous และ asynchronous
  • ทำงานได้หลาย languages และ platforms
  • Bi-directional streaming และ integrated auth
  • สามารถติดต่อกับ Services ต่าง ๆ ได้อย่างมีประสิทธิภาพ ไม่ว่าจะติดต่อกับ devices, mobile applications รวมถึง browsers ไปสู่ backend service
  • รองรับการ Scale, load balancing, tracing, health check หรือ จะเป็นการ authentication ก็ได้

จะดีแค่ไหนถ้า Service ของเราสามารถรับการสื่อสารได้ทั้งฝั่ง API Client และ
gRPC Service ทำให้งานเรามีประสิทธิภาพมากขึ้นในสื่อสารโดยไม่ต้องเลือกให้ Protocol สื่อสารทางใดทางหนึ่ง

--

--