Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
October 8, 2021 04:29 am GMT

Use gRPC with Node.js and Typescript

gRPC is a modern open-source high-performance Remote Procedure Call (RPC) framework that can run in any environment. And in this article, I am going to teach you how you can use gRPC to create high-performance RPC apps using node.js and typescript.

What is gRPC?

gRPC is a technology developed at Google in 2015. It is an RPC framework that will help you create RPC applications in many of your favorite languages. If you don't know what RPC is don't worry I'm going to explain it soon. This technology is used by google itself too. It is used quite a lot with microservice structures. according to Evaluating Performance of REST vs. gRPC from Ruwan Fernando gRPC is roughly 7 times faster than REST when receiving data and roughly 10 times faster than REST when sending data in the case he tested.

gRPC logo

What is RPC?

RPC is when a computer calls a procedure to execute in another address space. It is like calling another program to run action as it was ran on your computer and because of this, the request can be so much faster than REST.

Now lets go and create a simple application for sending hello messages.

Setup Project.

1- Initialize your project:

mkdir grpc-startercd grpc-starternpm init -y

2- Initialize typescript with your favorite config:

tsc init

I use the following as my typescript configuration in the tsconfig.json file. you can use whatever matches your need the best

{  "compilerOptions": {    "target": "es5",    "module": "commonjs",    "lib": [      "es6"    ],    "allowJs": true,    "outDir": "build",    "rootDir": "src",    "strict": true,    "noImplicitAny": true,    "esModuleInterop": true,    "resolveJsonModule": true  }}

3- create the folder structure:

  • /proto: proto buffers folder(I will explain more later)
  • /src: the source directory
  • /src/server: server directory
  • /src/client: client directory
  • /src/proto: auto generated code from proto buffers
grpc-starter/ proto/ src/     client/     proto/     server/

There are two ways to work with proto buffers and code generation in gRPC; dynamic or static. In static, we will generate types and code from our proto buffers but in dynamic we will not generate any typings from proto buffers and will use the code instead. dynamic can be a pretty good option if we were using JavaScript but since we need the typings to make our work easier while using TypeScript we will use the static way.

Create Proto Buffers

Proto Buffers are a way to serialize data. You may be very familiar with some other serialization languages like JSON and XML. Proto Buffers are just like them and it is developed by Google and wildly used with gRPC. In this article I'm not going to talk more about them, that's for another article.

First, we need to create the language enum. Well, you need to know a bit about folder structure in proto buffers we will create the language enum in /proto/com/language/v1/language.proto this is a package style folder structure that is necessary while using proto buffers with gRPC.

// /proto/com/language/v1/language.protosyntax = "proto3";package com.language.v1;message Language {  enum Code {    CODE_UNSPECIFIED = 0;    CODE_EN = 1;    CODE_FA = 2;  }}

Now we have to create our hello service in /proto/services/hello/v1/hello_service.proto.

// /proto/services/hello/v1/hello_service.protosyntax = "proto3";import "com/language/v1/language.proto";package services.hello.v1;service HelloService {  rpc Greet(GreetRequest) returns (GreetResponse) {}}message GreetRequest {  string name = 1;  com.language.v1.Language.Code language_code = 2;}message GreetResponse {  string greeting = 1;  reserved "language_code";  reserved 2;}

Buf

We will use a tool call Buf that will make code generation way easier for us. Check out the installation page to understand how you can install Buf.

Now we need to generate our buf config file at /proto/buf.yaml

# /proto/buf.yamlversion: v1beta1build:  roots:    - .lint:  use:    - DEFAULTbreaking:  use:    - WIRE_JSON

The v1 directory that we have in our folder structure is because of the linting setting that we are using you can default the linting setting and use a different folder structure if you wish. The linting structure has also affected some of my code that you can check in Buf Docs.

Now you can run the commands below in /proto directory to check your code:

$ buf ls-filescom\language\v1\language.protoservices\hello\v1\hello_service.proto

You can check your code for linting errors too. And if your proto buffers don't have any problem the command will return empty:

$ buf lint

If you have used the code provided by me and your buf version is 1.0.0-rc1 your lint command should return no error.

Generating code

Well for code generation you can use protoc as it's the more popular tool but working with protoc is exhausting so we are going to use buf.

Now you need to generate the buf generation config at /proto/buf.gen.yaml:

# /proto/buf.gen.yamlversion: v1beta1plugins:  - name: js    out: ../src/proto    opt: import_style=commonjs,binary  - name: grpc    out: ../src/proto    opt: grpc_js    path: grpc_tools_node_protoc_plugin  - name: ts    out: ../src/proto    opt: grpc_js

Now you have to install grpc-tools and grpc_tools_node_protoc_ts using npm or yarn. These two package will help us generate code for TypeScript using buf:

$ npm i -D grpc-tools grpc_tools_node_protoc_tsor$ yarn add -D grpc-tools grpc_tools_node_protoc_ts

Now you need to run the generate command inside /proto directory to generate code from proto buffers:

$ buf generate

Implement the server

First thing we need to do is to add the gRPC package to create our server:

$ npm i @grpc/grpc-jsor$ yarn add @grpc/grpc-js

Now create the /src/server/index.ts file and start the gRPC using the code below:

import {    Server,    ServerCredentials,} from '@grpc/grpc-js';const server = new Server();server.bindAsync('0.0.0.0:4000', ServerCredentials.createInsecure(), () => {    server.start();    console.log('server is running on 0.0.0.0:4000');});

Using this code we can create a new server and bind it to 0.0.0.0:4000 which is like starting an express server at port 4000.

Now we can take advantage of our statically generated code to create a typed Greet handler like below:

import {    ServerUnaryCall,    sendUnaryData,    Server,    ServerCredentials,} from '@grpc/grpc-js';import {Language} from '../proto/com/language/v1/language_pb';import {    GreetRequest,    GreetResponse,} from '../proto/services/hello/v1/hello_service_pb';const greet = (    call: ServerUnaryCall<GreetRequest, GreetResponse>,    callback: sendUnaryData<GreetResponse>) => {    const response = new GreetResponse();    switch (call.request.getLanguageCode()) {        case Language.Code.CODE_FA:            response.setGreeting(` ${call.request.getName()}`);            break;        case Language.Code.CODE_UNSPECIFIED:        case Language.Code.CODE_EN:        default:            response.setGreeting(`Hello, ${call.request.getName()}`);    }    callback(null, response);};...

Now we have to add the service to server:

...import {HelloServiceService} from '../proto/services/hello/v1/hello_service_grpc_pb';...server.addService(HelloServiceService, {greet});...

At the end your server file should look like something like this:

import {    ServerUnaryCall,    sendUnaryData,    Server,    ServerCredentials,} from '@grpc/grpc-js';import {Language} from '../proto/com/language/v1/language_pb';import {    GreetRequest,    GreetResponse,} from '../proto/services/hello/v1/hello_service_pb';import {HelloServiceService} from '../proto/services/hello/v1/hello_service_grpc_pb';const greet = (    call: ServerUnaryCall<GreetRequest, GreetResponse>,    callback: sendUnaryData<GreetResponse>) => {    const response = new GreetResponse();    switch (call.request.getLanguageCode()) {        case Language.Code.CODE_FA:            response.setGreeting(` ${call.request.getName()}`);            break;        case Language.Code.CODE_UNSPECIFIED:        case Language.Code.CODE_EN:        default:            response.setGreeting(`Hello, ${call.request.getName()}`);    }    callback(null, response);};const server = new Server();server.addService(HelloServiceService, {greet});server.bindAsync('0.0.0.0:4000', ServerCredentials.createInsecure(), () => {    server.start();    console.log('server is running on 0.0.0.0:4000');});

Now we can add nodemon to run our server and update it on change:

$ npm i nodemonor$ yarn add nodemon

And run the following command to start the server:

nodemon src/server/index.ts --watch /src/server

Now that we have our server ready let's go and create our client.

Implement the client

Create the /src/client/index.ts file to start writing the client code.

In the client first we need to connect to our service client using the code below:

import {credentials} from '@grpc/grpc-js';import {HelloServiceClient} from '../proto/services/hello/v1/hello_service_grpc_pb';const client = new HelloServiceClient('localhost:4000', credentials.createInsecure());

Now we can create the request and populate it with our values like below:

...import {Language} from '../proto/com/language/v1/language_pb';import {GreetRequest} from '../proto/services/hello/v1/hello_service_pb';...const request = new GreetRequest();request.setName('Aria');request.setLanguageCode(Language.Code.CODE_EN);

At the end you can send the request and receive the response:

...client.greet(request, (error, response) => {    if (error) {        console.error(error);        process.exit(1);    }    console.info(response.getGreeting());});

Your client file should look like this:

import {credentials} from '@grpc/grpc-js';import {Language} from '../proto/com/language/v1/language_pb';import {HelloServiceClient} from '../proto/services/hello/v1/hello_service_grpc_pb';import {GreetRequest} from '../proto/services/hello/v1/hello_service_pb';const client = new HelloServiceClient(    'localhost:4000',    credentials.createInsecure());const request = new GreetRequest();request.setName('Aria');request.setLanguageCode(Language.Code.CODE_EN);client.greet(request, (error, response) => {    if (error) {        console.error(error);        process.exit(1);    }    console.info(response.getGreeting());});

Run your client using the following command:

$ nodemon src/client/index.ts --watch src/client

Final words

Huge shoutout to Slavo Vojacek for his article on handling the proto buffers for typescript that has helped this article a lot.

You can check out the full repository at my GitHub repo

While gRPC is amazing and super fast but it is not the best practice to use it for freelancing projects and small projects cause it will cost you a lot of time compared to REST but if you are building a dream and you want it to be the best you can have gRPC as an option and think if it is worth the cost.

Resources

Find Me


Original Link: https://dev.to/devaddict/use-grpc-with-node-js-and-typescript-3c58

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To