In our previous tutorial, we have built a server to handle the bi-directional streams. Here we will build a bi-directional streaming client for the same with NodeJS.

The codebase has been shared on GitHub for your convenience as follows: https://github.com/techunits/bidirectional_grpc_sample_node

Prerequisite:

In order to implement the following tutorial, we need to have NodeJS 14+ installed on your system and the bi-directional gRPC streaming server is running successfully on the system.

Build the client:

As the server is running as a part of the prerequisite so we will assume that all the required dependencies have been installed on the system.

Load required packages:
const logger = require("elogger");
const grpc = require("@grpc/grpc-js");
const protoLoader = require("@grpc/proto-loader");
const faker = require("faker");
const slugify = require("slugify");
Load “article.proto” to load the gRPC data contract:
const packageDefinition = protoLoader.loadSync("./article.proto", {
    keepCase: true,
    longs: String,
    enums: String,
    defaults: true,
    oneofs: true
});
const articleManagerProto = grpc.loadPackageDefinition(packageDefinition).ArticleManagerPackage;
Initialize client & create stub based on the given proto:
const endpoint = "localhost:9111";
const serviceStub = new articleManagerProto.ArticleService(endpoint, grpc.credentials.createInsecure());
Create the service call:

The following call will initialize the RPC method which will be required to initialize the streaming as well as handle the response from the server.

const serviceCall = serviceStub.createBulkEntries();
Register events to fetch data:

This event handler will ensure that as soon as the server sends some data as a part of the successful processing of the stream, it will capture and proceed to the action accordingly. In our example, it will simply print the response back to the standard out console.

serviceCall.on("data", function(response) {
    logger.log(response);
});
Register event to handle error:

It might happen that the server is not able to process the data due to some validation failure or any other reason, so it will raise an exception. The following code snippet will handle the same and proceed accordingly. It will print to the standard error console in the given example.

serviceCall.on("error", function(error) {
    logger.error(error.code, " -> ", error.details);
});
Register event to handle call end:

We might need to process some additional business logic in a real-world scenario once the streaming is completed, so the following event handler will help to achieve the same.

serviceCall.on('end', function() {
    logger.debug(`Closed`);
});
Write to the stream:

The above code snippets will be used to handle different use cases once the server is sending back the response in terms of success or failure message. But in order to get to that stage we have to first write something to the stream as follows:

(async () => {
    const idxList = [1,2,3,4,5];
    for await (let i of idxList) {
        logger.debug(`Creating stream #${i}`);
        serviceCall.write({
            title: faker.lorem.sentence(),
            code: slugify(faker.lorem.words(2)),
            description: faker.lorem.paragraph()
        });
    }
})();

Here we are iterating the loop 5 times to send some set of data 5 times to the server via stream and the responses will be handler by the registered events.

New to gRPC?

If you just want to try out gRPC streaming capabilities, you may try our hosted gRPC mock interfaces at https://grpc.techunits.com/