📦 Define the gRPC API with Protocol Buffers

The commit added product.proto in api/proto/product/v1, defining the ProductService with full CRUD support:

protobuf
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.go
  • product_grpc.pb.go
text
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.proto

2. 🧠 Implement the gRPC Controller

The file internal/product/controller/grpc.go was added to wrap the existing product service logic in gRPC handlers:

go
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:

go
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:

go
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.mod and go.sum to include gRPC and protobuf dependencies
  • buf.gen.yaml to configure code generation with protoc-gen-go and protoc-gen-go-grpc

Buf.gen.yaml

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

Github Commit