Introduction to gRPC
If you like the free content I put out, consider subscribing to my newsletter on substack to get a well-researched article every week delivered straight to your inbox.
Today, there are different popular API architectural styles available. For example REST, SOAP, RPC(Remote Procedure Call), GraphQL, etc. Each API architecture style defines the principles of how the different services should communicate using the APIs, how the data exchange must happen, how API error handling must be done, etc.
What is gRPC?
gRPC is an open-source, cross-platform, high-performance Remote Procedure Call
gRPC is built on top of the HTTP/2 communication protocol and uses Protocol buffers(with file extension .proto) for data transfer. The protocol buffers take a small size in data transfer making them fast for data transmission on the network.
In gRPC, a client application can directly call an API of a server application on a different machine as if the client’s application was merely calling another function, making it easier for you to create distributed applications.
For example: in the below image, you can see that the server code is written in C++ and has a gRPC server associated with it. Different clients written in different languages have a gRPC stub and can connect with the server using the proto buffers request and get proto buffers response in return.
Protocol Buffers
When you would have used the REST API style to build your APIs, you most likely used JSON or XML to transfer the data over the network. JSON or XML formats are human-readable formats.
In gRPC, Protocol buffers(commonly called "protobufs") are the data exchange mechanism
Build a Golang App using gRPC
Alright, enough about theory. I did one practical example and built a client-server app in Golang using the gRPC framework. I suggest you do the same. This will help you visualize the true power of the gRPC framework. Here are the steps in the Golang:
Step 1: Install the protocol buffer compilers and the extra plugins that are required to generate the automated code using the proto files.
brew install protobuf
protoc --version
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
Refer to this guide for protocol buffer compiler installation.
Step 2: Create a directory, move into it, and initialize it as a go module
mkdir my-go-app
cd my-go-app
go mod init my-go-app
Step 3: Go language install libraries to a bin folder. You need to add the bin folder in the PATH environment so that the protobuf compiler can create the generated files. For example:
export PATH="$PATH:$GOPATH/bin/"
source ~/.zshrc
Step 4: Create the greeting.proto file inside the my-go-app/proto folder.
syntax = "proto3";
option go_package = "./proto";
package greeting;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse) {}
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string message = 1;
}
Step 5: Run this command to create the generated files.
protoc --go_out=. --go-grpc_out=. proto/greeting.proto
This command would generate the files: greeting.pb.go and greeting_grpc.pb.go. These files contain the boilerplate code for the client and the server interaction.
Step 6: Create the Client and the server files.
server.go
package main
import (
"context"
"fmt"
"log"
"net"
"google.golang.org/grpc"
pb "my-go-app/proto"
)
// Server implements the Greeter service defined in the .proto file.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements the SayHello RPC method.
func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloResponse, error) {
message := fmt.Sprintf("Hello, %s!", req.GetName())
return &pb.HelloResponse{Message: message}, nil
}
func main() {
// Set up a TCP listener on port 1234
lis, err := net.Listen("tcp", ":1234")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
// Create a new gRPC server
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Println("gRPC server is running on port 1234")
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
client.go
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "my-go-app/proto"
)
func main() {
// Set up a connection to the server
conn, err := grpc.Dial("localhost:1234", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := pb.NewGreeterClient(conn)
// Make a request to the server
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
response, err := client.SayHello(ctx, &pb.HelloRequest{Name: "Vivek"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Client received: %s", response.GetMessage())
}
Step 7: Run the server.go and the client.go and see the magic yourself.
go run server.go
-- Output
2024/11/02 09:30:27 gRPC server is running on port 1234
go run client.go
-- Output
2024/11/02 09:30:31 Client received: Hello, Vivek!
Takeaways
Now that you’ve built a full-fledged client-server using Golang, you can observe the following points about using the gRPC framework:
That’s it, folks for this edition of the newsletter. I hope you liked this edition. I will continue to write more about gRPC and Golang in the future editions.
Please consider liking 👍 and sharing with your friends as it motivates me to bring you good content for free. If you think I am doing a decent job, share this article in a nice summary with your network. Connect with me on Linkedin or Twitter for more technical posts in the future!
Curious Engineer is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.
Resources
Software engineer 2 @Amazon || 15k+ on Linkedin|| Ex Software engineer @Indmoney, Sprinklr||Ex Software Engineering intern @Phenom
11moNice explanation on gRPC and how data serialisation is an important part of network communication Here i have also explained different serialization processes https://www.linkedin.com/posts/sahil-wahi-2a947b1a9_part-2-for-covering-designing-data-intensive-activity-7227936420282167296-k1ck?utm_source=share&utm_medium=member_desktop
Engineering @ Zepto | Ex - Naukri.com, IndiaMart | Java | Spring Boot | GoLang | PHP
11moInsightful 🫡
Full Stack developer | content creator| open for collabs| freelancer
11monice share Vivek Bansal
Data | Software & Machine Learning Engineering | Kaggle Competitions Master
11moAwesome! It's an amazing concept for sure!
Senior C++ Engineer | Real-Time Streaming & Network Systems | WebRTC / HLS / CDN / Embedded Linux
11moIn its time CORBA was quite popular. It also has binary serialization on wire, Interface Definition Language (IDL) and stub generator, several open-source implementations and all that. Very promising thing. Until you get into debugging its generated boilerplate of course.