ข้ามไปยังเนื้อหา

gRPC-Gateway & Transcoding

ในโมดูล foundations เราพูดไว้ว่าระบบเดียวกันมักอยากได้ gRPC ภายในและ REST ที่ขอบนอก — call ที่เร็วและ typed ระหว่าง service ของตัวเอง แต่เป็น JSON ธรรมดาสำหรับ third party, browser และการเช็คด้วย curl เร็ว ๆ

Transcoding ให้คุณ serve ทั้งสองจาก .proto เดียวกัน คุณ annotate แต่ละ method ด้วย REST route ที่ควรตอบด้วย แล้ว reverse proxy ที่ generate มาจะแปล request แบบ JSON/HTTP ที่เข้ามาให้เป็น gRPC call และแปลง protobuf response กลับเป็น JSON

คุณอธิบาย REST mapping ไว้ใน service definition เลย โดยใช้ google.api.http annotation:

import "google/api/annotations.proto";
service UserService {
rpc GetUser(GetUserRequest) returns (User) {
option (google.api.http) = {
get: "/v1/users/{id}"
};
}
rpc CreateUser(CreateUserRequest) returns (User) {
option (google.api.http) = {
post: "/v1/users"
body: "*"
};
}
}

ตอนนี้ GetUser ตอบ GET /v1/users/42 ได้ด้วย — path segment {id} map เข้ากับ field id ของ request ส่วน CreateUser ตอบ POST /v1/users โดย JSON body map เข้ากับ request message ตัว gRPC method ไม่เปลี่ยน annotation แค่เพิ่มประตู REST เข้าไป

flowchart TB
  proto[".proto
+ google.api.http
annotations"] --> svc["UserService
(gRPC impl)"]
  internal["internal services
(native gRPC)"] --> svc
  ext["external client
GET /v1/users/42"] --> gw["grpc-gateway
reverse proxy"]
  gw -->|translates JSON↔protobuf| svc
service เดียวกัน เข้าถึงเป็น gRPC หรือ REST/JSON ก็ได้

gateway เป็น code ที่ generate มา (grpc-gateway ใน ecosystem ของ Go; Envoy ก็ทำ transcoding ผ่าน filter ได้) ตัว gateway จะ parse URL กับ JSON, สร้าง protobuf request, เรียก gRPC method จริง แล้ว marshal reply กลับเป็น JSON — ทั้งหมดขับเคลื่อนด้วย annotation

// Run the gateway alongside the gRPC server
mux := runtime.NewServeMux()
err := userv1.RegisterUserServiceHandlerFromEndpoint(
ctx, mux, "localhost:50051",
[]grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())},
)
if err != nil { log.Fatal(err) }
http.ListenAndServe(":8080", mux) // REST/JSON on :8080, gRPC on :50051
  • มี consumer ภายนอกหรือ browser ที่คาดหวัง REST/JSON แต่คุณไม่อยาก maintain API ตัวที่สองด้วยมือ transcoding ทำให้เหลือ contract เดียว
  • อยากได้ความ curl-ได้ และ OpenAPI doc annotation ชุดเดียวกัน generate OpenAPI spec ได้
  • ข้ามไปถ้าทุกอย่างอยู่ภายใน ถ้ามีแต่ service ของตัวเองที่เรียก API การเพิ่ม proxy hop และการแปลง JSON เป็น overhead ล้วน ๆ — อยู่กับ native gRPC ต่อไป
transcoding ให้คุณทำอะไรได้?
REST route ของ method ประกาศไว้ที่ไหน?
gateway ที่ generate มาทำอะไรจริง ๆ ตอน runtime?
เมื่อไรที่ transcoding ไม่คุ้ม?