Protostub is a Go library that simplifies generating client stubs and server scaffolding for gRPC services from Protocol Buffer (.proto
) definitions. It also provides a Command-Line Interface (CLI) for easy usage.
- Generate client and server code for gRPC services based on
.proto
files. - Easy-to-configure options for specifying source and destination directories.
- Command-Line Interface (CLI) for quick generation without needing to write Go code.
- Streamlines the setup of gRPC services in Go.
To install Protostub as a library, use:
go get github.com/lovelyoyrmia/protostub
To install the Protostub CLI, use:
go install github.com/lovelyoyrmia/protostub/cmd/protostub@latest
You can use the Protostub CLI to generate gRPC code directly from the command line. Here’s an example of how to run the CLI:
- Generate Server Command
protostub --proto_dir=./proto --dest_dir=./pb --service_dir=./services --type=server
- Generate Client Command
protostub --proto_dir=./proto --dest_dir=./pb --client_dir=./services --type=client
This command will generate Go and gRPC files in the specified destination directory based on the .proto
files found in the specified source directory.
If you prefer to use Protostub in your Go code, you can configure it as follows:
- Configure the Protostub:
package main
import (
"github.com/lovelyoyrmia/protostub"
"log"
)
func main() {
// Set the directory for your .proto files and the output directory for the generated code
stub := protostub.New(
protostub.WithProtoDir("./proto"),
protostub.WithDestDir("./generated"),
protostub.WithServiceDir("./service"),
protostub.WithClientDir("./client"),
protostub.WithType(protostub.ProtostubClientType),
)
// Generate the gRPC stubs
err := stub.Generate()
if err != nil {
log.Fatalf("failed to generate stubs: %v", err)
}
}
- Run the program to generate gRPC code from your
.proto
files.
go run main.go
This will generate Go and gRPC files in the specified destination directory.
-
CLI Options:
--proto_dir
: Specify the directory containing.proto
files.--dest_dir
: Specify the output directory for the generated Go and gRPC files.--service_dir
: Specify the directory for the generated Service implementation files.--client_dir
: Specify the directory for the generated client files.--type
: Specify the type of stub that will be generated (client or server).
-
Library Options:
- WithProtoDir(protoDir string): Specify the directory containing
.proto
files. - WithDestDir(destDir string): Specify the output directory for the generated Go and gRPC files.
- WithServiceDir(serviceDir string): Specify the output directory for the generated Service implementation files.
- WithClientDir(clientDir string): Specify the output directory for the generated client implementation files.
- WithType(typeName ProtoStubType): Specify the type of stub that will be generated (client or server)
- WithProtoDir(protoDir string): Specify the directory containing
Let's assume you have a simple .proto file named user.proto
syntax = "proto3";
package pb;
option go_package = "github.com/lovelyoyrmia/protostub/examples/pb";
message User {
string name = 1;
string email = 2;
int32 age = 3;
}
message GetUserRequest {
int32 id = 1;
}
message GetUserResponse {
User user = 1;
}
service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
- Generated Service Implementation
// Generated by Protostub
// see more examples: https://github.com/lovelyoyrmia/protostub
// Implement your logic below
package pb
import (
"context"
"log"
pb "github.com/lovelyoyrmia/protostub/examples/pb"
)
// UserServiceImpl implements the gRPC service for UserServiceImpl.
// This is the server struct that will be used to implement the service methods.
type UserServiceImpl struct {
pb.UnimplementedUserServiceServer
}
// GetUser handles requests for the GetUser method.
// It takes a GetUserRequest request and returns a GetUserResponse response.
func (s *UserServiceImpl) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
// TODO: Implement your logic here
log.Println("Received request:", req)
return &pb.GetUserResponse{}, nil
}
// NewUserServiceServer returns a new instance of UserServiceImpl.
// This is used to initialize the gRPC server with the service implementation.
func NewUserServiceServer() *UserServiceImpl {
return &UserServiceImpl{}
}
- Generated Client
package client
import (
pb "github.com/lovelyoyrmia/protostub/examples/pb"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
// UserServiceClient implements the gRPC client for UserService.
// It holds the gRPC client that will be used to make remote procedure calls to the UserService.
type UserServiceClient struct {
Client pb.UserServiceClient
}
// InitUserServiceClient initializes a new gRPC client for UserService.
// It takes a server URL as input, sets up a gRPC connection, and returns the initialized client.
//
// url: The address of the gRPC server to connect to.
//
// Returns:
// - A pointer to the initialized UserServiceClient.
// - An error if the connection setup fails.
func InitUserServiceClient(url string) (*UserServiceClient, error) {
cc, err := grpc.NewClient(url, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
}
c := UserServiceClient{
Client: pb.NewUserServiceClient(cc),
}
return &c, nil
}
For more examples you can see here.
- Separate Installation Instructions: Clearly distinguishes between installation for library use and CLI use.
- Clear Formatting: Ensures that the installation commands are easy to read.