Welcome to gRPC, Please Follow Me…
gRPCBackendAPIProtocol Buffers

Welcome to gRPC, Please Follow Me…

An introductory guide to gRPC covering fundamentals, benefits over REST, and practical implementation examples.

May 11, 2022
8 min read

Originally published on Ackee Blog on May 11, 2022

In this introductory guide to gRPC, I’ll explain the fundamentals of this high-performance, open-source universal RPC framework. I’ll cover the benefits of using gRPC over traditional REST APIs and provide guidance on setting up gRPC services, sharing insights from my experience implementing gRPC in production environments.

What is gRPC?

gRPC (gRPC Remote Procedure Calls) is a modern, open-source, high-performance RPC framework that can run in any environment. Originally developed by Google, it uses HTTP/2 for transport, Protocol Buffers as the interface description language, and provides features such as authentication, bidirectional streaming, flow control, blocking or nonblocking bindings, and cancellation and timeouts.

Why Choose gRPC Over REST?

1. Performance Benefits

HTTP/2 Foundation

  • Multiplexing: Multiple requests over a single connection
  • Header compression: Reduced overhead
  • Binary protocol: More efficient than text-based protocols

Protocol Buffers

  • Smaller payload sizes compared to JSON
  • Faster serialization/deserialization
  • Strong typing and validation

2. Type Safety and Code Generation

service UserService {
  rpc GetUser (GetUserRequest) returns (User);
  rpc CreateUser (CreateUserRequest) returns (User);
}

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;
}

This definition automatically generates strongly-typed client and server code in multiple languages.

gRPC Protocol Buffers

3. Streaming Support

gRPC supports four types of service methods:

  • Unary RPCs: Traditional request-response
  • Server streaming: Server sends multiple responses
  • Client streaming: Client sends multiple requests
  • Bidirectional streaming: Both sides stream independently

For more details on gRPC concepts, check the official documentation.

Setting Up Your First gRPC Service

1. Define Your Service

Create a .proto file:

syntax = "proto3";

package blog;

service BlogService {
  rpc GetPost (GetPostRequest) returns (Post);
  rpc ListPosts (ListPostsRequest) returns (ListPostsResponse);
  rpc CreatePost (CreatePostRequest) returns (Post);
}

message Post {
  int32 id = 1;
  string title = 2;
  string content = 3;
  string author = 4;
  int64 created_at = 5;
}

message GetPostRequest {
  int32 id = 1;
}

message ListPostsRequest {
  int32 page_size = 1;
  string page_token = 2;
}

message ListPostsResponse {
  repeated Post posts = 1;
  string next_page_token = 2;
}

message CreatePostRequest {
  string title = 1;
  string content = 2;
  string author = 3;
}

2. Generate Code

# Install protoc compiler and plugins
npm install -g @grpc/grpc-js @grpc/proto-loader

# Generate TypeScript definitions
protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts \
       --ts_out=grpc_js:./src/generated \
       --js_out=import_style=commonjs,binary:./src/generated \
       --grpc_out=grpc_js:./src/generated \
       blog.proto

3. Implement the Server

import * as grpc from '@grpc/grpc-js';
import { BlogServiceService } from './generated/blog_grpc_pb';
import { Post, GetPostRequest, CreatePostRequest } from './generated/blog_pb';

class BlogServiceImpl implements BlogServiceService {
  async getPost(
    call: grpc.ServerUnaryCall<GetPostRequest, Post>,
    callback: grpc.sendUnaryData<Post>
  ) {
    const request = call.request;
    const postId = request.getId();
    
    // Fetch post from database
    const post = await this.fetchPostFromDatabase(postId);
    
    callback(null, post);
  }

  async createPost(
    call: grpc.ServerUnaryCall<CreatePostRequest, Post>,
    callback: grpc.sendUnaryData<Post>
  ) {
    const request = call.request;
    
    // Create post in database
    const newPost = await this.createPostInDatabase({
      title: request.getTitle(),
      content: request.getContent(),
      author: request.getAuthor()
    });
    
    callback(null, newPost);
  }
}

// Start the server
const server = new grpc.Server();
server.addService(BlogServiceService, new BlogServiceImpl());

const port = process.env.PORT || 50051;
server.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () => {
  console.log(`gRPC server running on port ${port}`);
  server.start();
});

4. Create a Client

import * as grpc from '@grpc/grpc-js';
import { BlogServiceClient } from './generated/blog_grpc_pb';
import { GetPostRequest, CreatePostRequest } from './generated/blog_pb';

const client = new BlogServiceClient(
  'localhost:50051',
  grpc.credentials.createInsecure()
);

// Get a post
const getPostRequest = new GetPostRequest();
getPostRequest.setId(1);

client.getPost(getPostRequest, (error, response) => {
  if (error) {
    console.error('Error:', error);
    return;
  }
  
  console.log('Post:', response.toObject());
});

// Create a post
const createPostRequest = new CreatePostRequest();
createPostRequest.setTitle('My First gRPC Post');
createPostRequest.setContent('This is the content of my post');
createPostRequest.setAuthor('Jaroslav Šmolík');

client.createPost(createPostRequest, (error, response) => {
  if (error) {
    console.error('Error:', error);
    return;
  }
  
  console.log('Created post:', response.toObject());
});

Real-World Experience: Lessons Learned

Migration Strategy

When migrating from REST to gRPC:

  1. Start Small: Begin with internal services
  2. Gradual Migration: Keep REST for external APIs initially
  3. Gateway Pattern: Use gRPC-Gateway for HTTP compatibility

Useful Tools

  • BloomRPC: A GUI client for testing gRPC services
  • grpcurl: Command-line tool for interacting with gRPC servers
  • buf: Modern protocol buffer tooling
  • gRPC-Gateway: Generate reverse-proxy server from gRPC services

Performance Gains

In production, we observed:

  • 40% reduction in payload size
  • 60% improvement in latency for high-frequency calls
  • Better resource utilization due to connection multiplexing

Challenges Encountered

  1. Browser Support: Limited direct browser support (use gRPC-Web)
  2. Debugging: Less human-readable than REST (use tools like BloomRPC)
  3. Learning Curve: Team needed time to adapt to new patterns

For more information on gRPC status codes and error handling, see the gRPC documentation.

Conclusion

gRPC represents a significant advancement in service-to-service communication, offering performance, type safety, and feature richness that traditional REST APIs struggle to match. While there’s a learning curve and some limitations (especially for browser clients), the benefits often outweigh the costs for modern distributed systems.

The key to successful gRPC adoption is starting small, focusing on internal services first, and gradually expanding as your team becomes comfortable with the technology. The investment in learning gRPC pays dividends in improved performance, better developer experience, and more robust service communication.

Whether you’re building microservices, real-time applications, or high-performance APIs, gRPC deserves serious consideration as your communication protocol of choice. Welcome to the world of modern RPC—I hope this guide helps you get started on your gRPC journey!