Creating a gRPC Client as a Local npm Package
Tags: node, grpc, npm
Published: 2020-11-01 15:13:28

Making a local npm package is relatively easy - you create a new Node.js project.
```
npm init
```
The sole purpose of this package is to have one client for each service that can be easily imported and used by other services. It uses the protobuf packages I created earlier.

I made the entry point to the package `<name_of_service>.js`, install the protobuf package needed, and gRPC:
```
npm install --save <path_to_package> @grpc/grpc-js
```
I then set up my file:
```javascript
const grpc = require('@grpc/grpc-js');
const { 
  <name_of_service>Services,
  <name of message>Messages } = require('<name_of_package');
const packageDefinition = grpc.loadPackageDefinition(<name_of_service>Services);
const meta = new grpc.Metadata();
```
gRPC now knows to use the generated package definition, and which messages I need to use for this client.

**Note on Messages**
When using the generated files, you have to explicitly set up the messages.  I did not have to do this originally using the raw `*.proto` files.

I also set up the metadata object that will be filled as needed by each operation.

I then set up a class that will be the export of the file:
```javascript
class <name_of_service>Client {
  constructor(pathToService) {
    this.client = new packageDefinition.<name_of_service>(
      pathToService,
      grpc.credentials.createInsecure()
    );
  }
...
```
I use the `constructor` to import the path to the service that the client is for, and then actually instantiate the client.  I also use it to import any global variables needed, typically any metadata that needs to be sent with the request.

I then write any logic needed.  Because these clients are to be "universal", I keep it very simple.  

I create a helper function for creating the messages needed for each operation.
```javascript
async createRequestMessage(request, type) {
  let message;
  
  switch (type) {
    case <type>:
    message = new <name of message>Messages.<message>();
    message.set<field>(request.<field>);
  }
  return message;
}
```
The generated files creates a constructor class for each message it finds.  So I start by instantiating a new instance of that class and using the `.set*` syntax to actually put my data in the class.  This gets interesting with some of the field types, which I will discuss in later posts.

I then create an async function for each operation in the service. 
```javascript
...
async nameOfOperation(request) {
  meta.set('<key>', <value>);
  const messsage = await this.createRequestMessage(request, <type>);
  const promise = new Promise((resolve, reject) => {
      this.client.<name_of_operation>(message, meta, (err, res) => {
        if (err) {
          reject(err);
        } else {
          resolve(res);
        }
      });
    });

    return promise.then(value => {
      return value;
    });
  }
```
- I start by setting any metadata needed by the receiving service.  
- Then I send my request off to be turned into a gRPC approved message. 
- I then create an explicit `Promise` to receive the response from the service.  Since gRPC is synchronous by nature, I found this approach works the best. 
- Once the `Promise` as been resolved or rejected, I return the value to the function that originally called it.

And then I export the class.
```javascript
module.exports = <name_of_class>;
```
I like to use the `module.exports` syntax over `export default` because it is explicit and easy for another developer to follow.

Because the clients are being used by multiple services for various reasons, it made sense to me to have them simply receive the request and return the response, thus allowing the service do what it needed to do with the response.

My clients can now be imported as npm packages to other services and used.