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

Code Generation

ไฟล์ .proto ตัวเดียวทำอะไรไม่ได้ คุณต้องรันไฟล์นั้นผ่าน protoc ที่เป็น compiler ของ Protocol Buffers ที่ parse schema แล้วส่งต่อให้ plugin ที่ emit code สำหรับภาษาใดภาษาหนึ่ง ตัว protoc เองไม่รู้จัก Go หรือ Python เลย — plugin ต่างหากที่รู้

สำหรับ gRPC ปกติจะมี output สอง ส่วน:

  • Message code — struct/class ของ User, GetUserRequest ฯลฯ (มาจาก plugin protobuf พื้นฐาน)
  • Service code — client stub และ server interface (มาจาก plugin ของ gRPC)
flowchart LR
  proto["user.proto"] --> protoc["protoc
(parses schema)"]
  protoc --> base["protobuf plugin
→ message types"]
  protoc --> grpc["gRPC plugin
→ stub + server interface"]
protoc parse; plugin emit code ของแต่ละภาษา

แต่ละภาษามี plugin คู่ของตัวเอง นี่คือคำสั่งทั่วไปของแต่ละ ecosystem:

Terminal window
# install the two plugins once
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
user/v1/user.proto
# → user.pb.go (messages) + user_grpc.pb.go (stub + server interface)

ไม่ว่าภาษาไหน generated code จะมีของ 3 อย่างเดิมเสมอ:

  1. Message type — object ที่มี type สำหรับทุก message พร้อม getter/setter หรือ field และ logic การ serialize ฝังมาให้แล้ว
  2. Client stub — class ที่มี method หนึ่งตัวต่อ rpc เพื่อให้ client แค่เรียก stub.GetUser(req)
  3. Server interface — base แบบ abstract (Go interface, Python servicer, Node service definition) ที่มี method หนึ่งตัวต่อ rpc ให้คุณ implement

คุณจะไม่แก้ไฟล์ที่ generate มา เมื่อ .proto เปลี่ยน คุณ generate ใหม่

คำสั่ง protoc ดิบ ๆ จะยุ่งเร็วมาก — path ของ plugin, include path, option ของ output คูณด้วยจำนวนภาษา buf คือเครื่องมือยุคใหม่ที่มาแทน คุณประกาศ input กับ output ใน config file เล็ก ๆ แล้วรันคำสั่งเดียว:

buf.gen.yaml
version: v2
plugins:
- remote: buf.build/protocolbuffers/go
out: gen
- remote: buf.build/grpc/go
out: gen
Terminal window
buf generate

buf ยัง lint schema และตรวจจับ breaking change ให้ด้วย (เจาะลึกในโมดูล Ecosystem) — จึงเป็นเหตุผลที่ทีมส่วนใหญ่เลือกใช้เป็นมาตรฐาน

protoc กับ plugin ของตัวเองมีบทบาทต่างกันอย่างไร?
code generation ของ gRPC ผลิต artifact 3 อย่างอะไรบ้าง?
เมื่อ .proto เปลี่ยน คุณควรทำอะไร?
ทำไมทีมส่วนใหญ่ถึงใช้ buf แทนคำสั่ง protoc ดิบ ๆ?