API and API Design: How gRPC APIs Work?

We will discuss one API style called gRPC, we will look at how gRPC works and the different components of gRPC.

In partnership with

Hello “👋

Welcome to another week, another opportunity to become a Great Backend Engineer.

Today’s issue is brought to you by Masteringbackend → A great resource for backend engineers. We offer next-level backend engineering training and exclusive resources.

Before we get started, I have a few announcements:

I have a special gift for you: You will love this one.

The fastest way to build AI apps

We’re excited to introduce Writer AI Studio, the fastest way to build AI apps, products, and features. Writer’s unique full-stack design makes it easy to prototype, deploy, and test AI apps – allowing developers to build with APIs, a drag-and-drop open-source Python framework, or a no-code builder, so you have flexibility to build the way you want.

Writer comes with a suite of top-ranking LLMs and has built-in RAG for easy integration with your data. Check it out if you’re looking to streamline how you build and integrate AI apps.

Now, back to the business of today.

In my previous series, I explored everything you need to know and learn about API and API Designs: Different API Styles.

Today, we will discuss one API style called gRPC, we will look at how gRPC works and the different components of gRPC.

This comes from my Backend Engineering Hub under the API and API Design section. However, I’m only transferring the knowledge here and breaking it down in this series one topic at a time.

How Does gRPC Work?

In the realm of modern distributed systems, gRPC has emerged as a high-performance framework for building efficient and scalable APIs. Developed by Google, gRPC (short for gRPC Remote Procedure Call) builds on HTTP/2 and Protocol Buffers (Protobuf) to deliver low-latency communication, strong typing, and cross-platform interoperability.

We’ll dive into the inner workings of gRPC, explaining its components, benefits, and real-world applications.

What Is gRPC?

gRPC is an open-source, high-performance framework that enables seamless communication between client and server applications. Unlike REST, which revolves around resources and HTTP verbs, gRPC uses a Remote Procedure Call (RPC) model, allowing clients to invoke methods on a remote server as if they were local function calls.

Key features of gRPC include:

  • Efficient Serialization with Protocol Buffers.

  • Full-Duplex Streaming using HTTP/2.

  • Multi-language Support, enabling polyglot microservices.

  • Bidirectional Communication, making it ideal for real-time applications.

How Does gRPC Work?

To understand how gRPC works, let’s break it down into its core components and processes:

Install Required Packages

Before we start, install the necessary dependencies:

npm init -y
npm install @grpc/grpc-js @grpc/proto-loader

Defining the Service

At the heart of gRPC is the service definition, written in Protocol Buffers (Protobuf). Protobuf is a language-neutral and platform-independent mechanism for serializing structured data, enabling high-speed communication. The service definition specifies:

  • The methods available.

  • The request and response data types.

Here’s an example of a Protobuf definition for a simple user service:

syntax = "proto3";

service UserService {
  // Unary RPC
  rpc GetUser (UserRequest) returns (UserResponse);

  // Server-streaming RPC
  rpc ListUsers (EmptyRequest) returns (stream UserResponse);
}

message UserRequest {
  int32 id = 1;
}

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

message EmptyRequest {}

Implement the gRPC Server

Create a file named server.js:

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const PROTO_PATH = './user.proto';

// Load the Protobuf file
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});

const userProto = grpc.loadPackageDefinition(packageDefinition).UserService;

// Sample user data
const users = {
  1: { id: 1, name: 'Alice', email: '[email protected]' },
  2: { id: 2, name: 'Bob', email: '[email protected]' },
};

// Implement the GetUser RPC
function getUser(call, callback) {
  const user = users[call.request.id];
  if (user) {
    callback(null, user);
  } else {
    callback({
      code: grpc.status.NOT_FOUND,
      details: 'User not found',
    });
  }
}

// Implement the ListUsers RPC
function listUsers(call) {
  Object.values(users).forEach((user) => call.write(user));
  call.end();
}

// Start the gRPC server
function main() {
  const server = new grpc.Server();
  server.addService(userProto.service, { GetUser: getUser, ListUsers: listUsers });
  server.bindAsync('0.0.0.0:50051', grpc.ServerCredentials.createInsecure(), () => {
    console.log('Server running at http://0.0.0.0:50051');
    server.start();
  });
}

main();

Implement the gRPC Client

Create a file named client.js:

const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const PROTO_PATH = './user.proto';

// Load the Protobuf file
const packageDefinition = protoLoader.loadSync(PROTO_PATH, {
  keepCase: true,
  longs: String,
  enums: String,
  defaults: true,
  oneofs: true,
});
const userProto = grpc.loadPackageDefinition(packageDefinition).UserService;

function main() {
  const client = new userProto('localhost:50051', grpc.credentials.createInsecure());

  // Unary RPC: GetUser
  client.GetUser({ id: 1 }, (error, response) => {
    if (!error) {
      console.log('User:', response);
    } else {
      console.error('Error:', error.message);
    }
  });

  // Server-streaming RPC: ListUsers
  const call = client.ListUsers({});
  call.on('data', (user) => {
    console.log('User:', user);
  });
  call.on('end', () => {
    console.log('Finished receiving user list.');
  });
}

main();

Explanation of the Code

Here I will try to explain the code above here.

  1. Server:

    • Implements the GetUser method for retrieving a single user by ID.

    • Implements the ListUsers method for streaming all users.

  2. Client:

    • Uses the GetUser method to fetch a single user.

    • Uses the ListUsers method to stream multiple users.

  3. Protocol Buffers:

    • Defines the service and message structure in a compact and efficient format.

    • Automatically generates bindings for the server and client.

  4. HTTP/2:

    • Enables efficient communication between the client and server.

Key Benefits of gRPC

  1. High Performance: Protobuf serialization and HTTP/2 reduce payload size and latency, making gRPC faster than REST.

  2. Strong Typing: Protobuf enforces strict typing, reducing runtime errors and improving data validation.

  3. Cross-Language Interoperability: gRPC supports multiple languages, enabling seamless integration across diverse systems.

  4. Streaming Capabilities: Full-duplex streaming makes gRPC ideal for real-time applications.

  5. Code Generation: Automatic generation of client and server code accelerates development.

Real-World Applications of gRPC

  • Microservices Communication: gRPC excels in internal communication between microservices, where performance and efficiency are critical.

  • Mobile and IoT Applications: gRPC’s compact payloads and HTTP/2 support make it ideal for devices with limited bandwidth.

  • Real-Time Systems: Use cases like live chat, video streaming, and financial trading benefit from gRPC’s streaming capabilities.

gRPC revolutionizes how applications communicate by combining the power of Protocol Buffers, HTTP/2, and a robust RPC model. Its ability to handle diverse communication patterns, deliver high performance, and integrate across languages makes it a top choice for modern API design.

Did you learn any new things from this newsletter this week? Please reply to this email and let me know. Feedback like this encourages me to keep going.

See you on Next Week.

Remember to start learning backend engineering from our courses:

Backend Engineering Resources

Whenever you're ready

There are 4 ways I can help you become a great backend engineer:

1. The MB Platform: Join 1000+ backend engineers learning backend engineering on the MB platform. Build real-world backend projects, track your learnings and set schedules, learn from expert-vetted courses and roadmaps, and solve backend engineering tasks, exercises, and challenges.

2. ​The MB Academy:​ The “MB Academy” is a 6-month intensive Advanced Backend Engineering BootCamp to produce great backend engineers.

3. MB Video-Based Courses: Join 1000+ backend engineers who learn from our meticulously crafted courses designed to empower you with the knowledge and skills you need to excel in backend development.

4. GetBackendJobs: Access 1000+ tailored backend engineering jobs, manage and track all your job applications, create a job streak, and never miss applying. Lastly, you can hire backend engineers anywhere in the world.

LAST WORD đź‘‹ 

How am I doing?

I love hearing from readers, and I'm always looking for feedback. How am I doing with The Backend Weekly? Is there anything you'd like to see more or less of? Which aspects of the newsletter do you enjoy the most?

Hit reply and say hello - I'd love to hear from you!

Stay awesome,
Solomon

I moved my newsletter from Substack to Beehiiv, and it's been an amazing journey. Start yours here.

Reply

or to participate.