Code Generation
compiler กับ plugin ของตัวเอง
หัวข้อที่มีชื่อว่า “compiler กับ plugin ของตัวเอง”ไฟล์ .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"]
รันแยกตามภาษา
หัวข้อที่มีชื่อว่า “รันแยกตามภาษา”แต่ละภาษามี plugin คู่ของตัวเอง นี่คือคำสั่งทั่วไปของแต่ละ ecosystem:
# install the two plugins oncego install google.golang.org/protobuf/cmd/protoc-gen-go@latestgo 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)pip install grpcio-tools
python -m grpc_tools.protoc -I. \ --python_out=. --grpc_python_out=. \ user/v1/user.proto# → user_pb2.py (messages) + user_pb2_grpc.py (stub + servicer)npm install --save-dev ts-proto @grpc/grpc-js grpc-tools
protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto \ --ts_proto_out=. --ts_proto_opt=outputServices=grpc-js \ user/v1/user.proto# → user.ts (typed messages + client + server interfaces)สิ่งที่ได้ออกมาจริง ๆ
หัวข้อที่มีชื่อว่า “สิ่งที่ได้ออกมาจริง ๆ”ไม่ว่าภาษาไหน generated code จะมีของ 3 อย่างเดิมเสมอ:
- Message type — object ที่มี type สำหรับทุก
messageพร้อม getter/setter หรือ field และ logic การ serialize ฝังมาให้แล้ว - Client stub — class ที่มี method หนึ่งตัวต่อ
rpcเพื่อให้ client แค่เรียกstub.GetUser(req) - Server interface — base แบบ abstract (Go interface, Python servicer, Node service definition) ที่มี method หนึ่งตัวต่อ
rpcให้คุณ implement
คุณจะไม่แก้ไฟล์ที่ generate มา เมื่อ .proto เปลี่ยน คุณ generate ใหม่
ใช้ buf แทน protoc ดิบ ๆ
หัวข้อที่มีชื่อว่า “ใช้ buf แทน protoc ดิบ ๆ”คำสั่ง protoc ดิบ ๆ จะยุ่งเร็วมาก — path ของ plugin, include path, option ของ output คูณด้วยจำนวนภาษา buf คือเครื่องมือยุคใหม่ที่มาแทน คุณประกาศ input กับ output ใน config file เล็ก ๆ แล้วรันคำสั่งเดียว:
version: v2plugins: - remote: buf.build/protocolbuffers/go out: gen - remote: buf.build/grpc/go out: genbuf generatebuf ยัง lint schema และตรวจจับ breaking change ให้ด้วย (เจาะลึกในโมดูล Ecosystem) — จึงเป็นเหตุผลที่ทีมส่วนใหญ่เลือกใช้เป็นมาตรฐาน