Lesson 3 · Foundations
Services & codegen
From service { rpc … } to a Go interface you implement.
Your win: declare a service, and explain exactly what
make gen-proto-go produces — and the surprising truth that this repo
generates with protoc, not buf.
A service is a set of RPC methods
Add a service block to your .proto; each rpc
line is one method with a request and a response message.1
service EmailModifierService {
rpc SendEmail(SendEmailRequest) returns (SendEmailResponse);
rpc BulkSendEmails(BulkSendEmailsRequest) returns (BulkSendEmailsResponse);
}
What codegen produces
A code generator turns that into Go. For each service you get three things:
XServiceServer
An interface with one Go method per rpc. You implement this — it's your handler type.
RegisterXServiceServer
A function to attach your implementation to a running grpc.Server.
XServiceClient
The stub — callers use it to invoke the methods remotely (Lesson 1's f.client).
protoc, not buf generate
make gen-proto-go runs protoc (via
proto/gen_go.sh in Docker) with the
protoc-gen-go (messages), protoc-gen-go-grpc (service +
client), and gateway plugins, writing to pkg/manabuf/. buf is
used only for linting & breaking-change checks (make lint-proto).
The repo rule is explicit: don't run local buf generate.
Registration wires your implementation in (`SetupGRPC` calls the generated registrar):
cmd/server/spike/init_grpc.go:10spb.RegisterEmailModifierServiceServer(server, emailModifierSvc) // your impl
// callers elsewhere: spb.NewEmailModifierServiceClient(conn)
Unimplemented twist
Our codegen passes require_unimplemented_servers=false
(proto/gen_go.sh), so your server type does
not need to embed UnimplementedXServer — though some
transport structs still do it for forward-compatibility (recall Go course, Lesson 8 on
embedding). Without that flag, forgetting the embed is a compile error.
gRPC — Go Quick start (protoc plugins) + Buf docs
The quickstart shows installing protoc-gen-go/-go-grpc and
generating stubs — the same plugins our gen_go.sh runs. Buf docs cover the
lint/breaking rules we do use.
→ grpc.io/docs/languages/go/quickstart
→ buf.build/docs (lint & breaking)
Check yourself (from memory)
Q1. In this repo, Go stubs are generated by…
protoc through proto/gen_go.sh.
A common wrong assumption is that buf generates — here it only lints.
Q2. In this repo, buf is used for…
make lint-proto — style + breaking-change
detection (guarding the field-number rule from Lesson 2). Not codegen.
Q3. Codegen produces, for each service, a…
XServiceServer interface (you implement),
a Register… func, and an XServiceClient stub.
make gen-proto-go produce from a service, and what do you write?protoc (not buf) via proto/gen_go.sh
to generate, per service: the message structs, an XServiceServer
interface, a RegisterXServiceServer function, and an
XServiceClient stub — under pkg/manabuf. You
write the Go type that implements the server interface (the handler methods).
buf only lints / breaking-checks the proto.protoc flags in gen_go.sh, or how the
gateway plugin fits in? Ask me.