📦 Define the gRPC API with Protocol Buffers
The commit added product.proto in api/proto/product/v1, defining the ProductService with full CRUD support:
syntax = "proto3";
package product.v1;
option go_package = "github.com/mobintmu/go-simple/api/proto/product/v1";
import "google/protobuf/empty.proto";
message ProductRequest {
int32 id = 1;
}
message ProductResponse {
int32 id = 1;
string name = 2;
string description = 3;
int64 price = 4;
}
message CreateProductRequest {
string name = 1;
string description = 2;
int64 price = 3;
}
message UpdateProductRequest {
int32 id = 1;
string name = 2;
string description = 3;
int64 price = 4;
}
message DeleteProductRequest {
int32 id = 1;
}
message ListProductsResponse {
repeated ProductResponse products = 1;
}
service ProductService {
rpc GetProductByID(ProductRequest) returns (ProductResponse);
rpc CreateProduct(CreateProductRequest) returns (ProductResponse);
rpc UpdateProduct(UpdateProductRequest) returns (ProductResponse);
rpc DeleteProduct(DeleteProductRequest) returns (ProductResponse);
rpc ListProducts(google.protobuf.Empty) returns (ListProductsResponse);
}This schema was compiled using protoc, generating:
product.pb.goproduct_grpc.pb.go
protoc -I. --go_out=. --go_opt=paths=source_relative --go-grpc_out=.
--go-grpc_opt=paths=source_relative --grpc-gateway_out=. --grpc-gateway_opt=paths=source_relative
api/proto/product/v1/product.proto2. 🧠 Implement the gRPC Controller
The file internal/product/controller/grpc.go was added to wrap the existing product service logic in gRPC handlers:
type ProductGRPC struct {
productv1.UnimplementedProductServiceServer svc *service.Product
}
func NewProductGRPC(svc *service.Product) productv1.ProductServiceServer {
return &ProductGRPC{
svc: svc
}
}Each RPC method (e.g. GetProductByID, CreateProduct) maps to the corresponding service method, ensuring consistent behavior across HTTP and gRPC.
3. 🛠️ Setup the gRPC Server with Uber FX
The file internal/server/grpc.go defines NewGRPCServer, which registers the gRPC service and starts the server using FX lifecycle hooks:
func NewGRPCServer(p Params) *grpc.Server {
server := grpc.NewServer() productv1.RegisterProductServiceServer(server, p.Product)...
}This allows the server to start automatically when the app runs.
4. 🧪 Add gRPC Tests
The commit also added test/product_grpc_test.go, which tests the GetProductByID method using a real gRPC client:
conn, err := grpc.Dial("localhost:9090",
grpc.WithTransportCredentials(insecure.NewCredentials()))client :=
productv1.NewProductServiceClient(conn)resp, err := client.GetProductByID(context.Background(),
&productv1.ProductRequest{Id: 1})This ensures the gRPC server is correctly wired and responds as expected.
5. 📄 Update Project Configuration
The commit updated:
go.modandgo.sumto include gRPC and protobuf dependenciesbuf.gen.yamlto configure code generation withprotoc-gen-goandprotoc-gen-go-grpc
Buf.gen.yaml
version: v2plugins: - local: protoc-gen-go out: gen/go opt: - paths=source_relative -
local: protoc-gen-go-grpc out: gen/go opt: - paths=source_relative✅ Summary
This commit laid the foundation for gRPC in go-simple by:
- Defining a complete gRPC API
- Implementing controller logic
- Wiring the server with Uber FX
- Adding integration tests
