grpc in a nutshell

Published on
Hamed Gholami-
4 min read

Overview

a comprehensive sample for a .proto file



syntax = "proto3";

package example;

// Importing necessary options for HTTP mapping (e.g., for use with grpc-gateway).
import "google/api/annotations.proto";

// The greeting service definition.
service GreetingService {
  // A simple RPC method that gets a greeting message for a given name.
  rpc SayHello (HelloRequest) returns (HelloReply) {
    option (google.api.http) = {
      get: "/v1/example/echo/{name}"
    };
  };

  // A server streaming RPC method that sends multiple greeting messages.
  rpc LotsOfReplies (HelloRequest) returns (stream HelloReply) {}

  // A client streaming RPC method that receives a stream of messages.
  rpc LotsOfGreetings (stream HelloRequest) returns (HelloReply) {}

  // A Bidirectional streaming RPC method.
  rpc BidiHello (stream HelloRequest) returns (stream HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

// An example of a complex message type with various field types.
message ComplexMessage {
  string string_field = 1;
  bool bool_field = 2;
  int32 int_field = 3;
  float float_field = 4;
  NestedMessage nested_field = 5;

  // An example of an enum within a message.
  enum SampleEnum {
    UNKNOWN = 0;
    STARTED = 1;
    RUNNING = 2;
  }

  SampleEnum status = 6;

  // An example of repeated fields (similar to arrays).
  repeated string string_list = 7;

  // An example of a map field (similar to a dictionary or hash map).
  map<string, NestedMessage> map_field = 8;

  // An example of a oneof field, where only one of the fields can be set.
  oneof test_oneof {
    string name = 9;
    int32 id = 10;
  }
}

// An example of a nested message.
message NestedMessage {
  string some_value = 1;
}


// ** protocol buffers use message elements to define both parameter types and return types

a simple grpc client-server communication

Step 1: Define the .proto file

Let's start with the greeting.proto file we discussed earlier, which defines a simple GreetingService:


syntax = "proto3";

package greeting;

// The greeting service definition.
service GreetingService {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

Save this content into a file named greeting.proto.

Step 2: Generate the gRPC code

Use the grpc-tools package to generate the gRPC client and server code based on your .proto file.

npm install -g grpc-tools
grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./server --grpc_out=./server --proto_path=./ greeting.proto

This command generates greeting_pb.js and greeting_grpc_pb.js in the ./server directory. These files contain the JavaScript objects and service stubs for your gRPC service.

Step 3: Implement the server

Now create a file named server.js for your gRPC server.

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync('greeting.proto', {});
const greetingPackage = grpc.loadPackageDefinition(packageDefinition).greeting;

// Implement the SayHello RPC method.
function sayHello(call, callback) {
  callback(null, { message: 'Hello ' + call.request.name });
}

// Main server function
function main() {
  const server = new grpc.Server();
  server.addService(greetingPackage.GreetingService.service, { sayHello: sayHello });
  server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure());
  console.log('Server running at http://0.0.0.0:50051');
  server.start();
}

main();

This code sets up a gRPC server that listens on port 50051 and responds to SayHello RPC calls by sending back a greeting message.

Step 4: Implement the client

Next, create a file named client.js for your gRPC client.

const grpc = require('grpc');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync('greeting.proto', {});
const greetingPackage = grpc.loadPackageDefinition(packageDefinition).greeting;

function main() {
  const client = new greetingPackage.GreetingService(
    'localhost:50051',
    grpc.credentials.createInsecure()
  );
  client.sayHello({ name: 'World' }, function (err, response) {
    console.log('Greeting:', response.message);
  });
}

main();

This client code creates a new GreetingService client that connects to our server on localhost:50051 and sends a SayHello RPC with the name "World".

Step 5: Install Dependencies and Run

First, you need to install the necessary Node.js packages:

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

Now you can start your gRPC server:

node server.js

And in a separate terminal, run your gRPC client:

node client.js

When you run the client, you should see the output:

Greeting: Hello World

This is a very basic example to get you started with gRPC in Node.js. Real-world applications typically involve more complex setups, including bidirectional streaming, error handling, authentication, and more. However, this should provide a clear and understandable foundation for creating gRPC applications.