gRPC in Go - Part 1: Understanding the Basics
gRPC is becoming increasingly popular for building efficient microservices, but getting started can feel overwhelming. In this first part of our series, we'll break down the basics of gRPC and set up our first Protocol Buffers definitions for an e-commerce system.
What is gRPC?
gRPC is a high-performance RPC (Remote Procedure Call) framework that can run in any environment. It uses Protocol Buffers as its interface definition language, enabling you to define your service contract in a language-agnostic way.
Setting Up Our Project
First, let's create a new Go project and install the necessary dependencies:
mkdir ecommerce-grpc
cd ecommerce-grpc
go mod init github.com/andredeloliveira/ecommerce-grpc
go get google.golang.org/grpc
go get google.golang.org/protobuf
Defining Our Protocol Buffers
Let's create our first proto file for the product service. Create a file named product.proto
:
syntax = "proto3";
package ecommerce;
option go_package = "github.com/andredeloliveira/ecommerce-grpc";
service ProductService {
rpc GetProduct(ProductID) returns (Product) {}
rpc ListProducts(ProductListRequest) returns (ProductList) {}
}
message ProductID {
string id = 1;
}
message Product {
string id = 1;
string name = 2;
string description = 3;
double price = 4;
int32 stock = 5;
}
message ProductListRequest {
int32 page = 1;
int32 limit = 2;
}
message ProductList {
repeated Product products = 1;
int32 total = 2;
}
Generating Go Code
To generate Go code from our proto file, we'll need the protocol compiler (protoc) and the Go plugin. Here's how to generate the code:
mkdir ecommerce-proto
protoc --go_out=./ecommerce-proto --go_opt=paths=source_relative \
--go-grpc_out=./ecommerce-proto --go-grpc_opt=paths=source_relative \
product.proto
This will generate two files:
product.pb.go
: Contains the Go structs for our messagesproduct_grpc.pb.go
: Contains the service definitions and interfaces
Understanding the Generated Code
The generated code provides us with interfaces and types we'll use to implement our service. Here's the UnimplementedProductServiceServer
, with the methods that we defined on our protobuf file.
// product_grpc.pb.go
type UnimplementedProductServiceServer struct{}
func (UnimplementedProductServiceServer) GetProduct(context.Context, *ProductID) (*Product, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetProduct not implemented")
}
func (UnimplementedProductServiceServer) ListProducts(context.Context, *ProductListRequest) (*ProductList, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListProducts not implemented")
}
This way, we can internally define an interface, like shown:
type ProductServiceServer interface {
GetProduct(context.Context, *ProductID) (*Product, error)
ListProducts(context.Context, *ProductListRequest) (*ProductList, error)
}
This interface defines the methods our server needs to implement to handle product-related requests.
Next Steps
In the next part of this series, we'll implement the server side of our e-commerce application, including:
- Creating a product service implementation
- Setting up the gRPC server
- Handling requests and responses
- Implementing error handling
Stay tuned for Part 2!