npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@getezy/grpc-client

v1.0.11

Published

Universal, extendable, typesafe gRPC/gRPC-Web client for node used in ezy.

Downloads

71

Readme

🛵 Universal, extendable, typesafe gRPC/gRPC-Web client for node used in ezy.

npm npm Codacy Badge Codacy Badge

esm cjs

Warning
This lib is not production ready until it is merged to main ezy project.

Installation

npm i @getezy/grpc-client

Usage

This library was designed to be extendable as much as possible. To start you need GrpcClient, Loader and Protocol.

Use GrpcClientFactory for creating GrpcClient instance.

GrpcClientFactory.create(loader: AbstractLoader, protocol: AbstractProtocol): Promise<GrpcClient>

import { GrpcClientFactory, GrpcProtocol, ProtobufLoader } from '@getezy/grpc-client';
import * as path from 'node:path';

const client = await GrpcClientFactory.create(
  new ProtobufLoader(path.join(__dirname, '../proto/main.proto')),
  new GrpcProtocol({ address: '10.10.10.10' })
);

const payload = { id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' };
const metadata = { 'x-access-token': 'token' };
const response = await client.invokeUnaryRequest<Request, Response>(
  { service: 'simple_package.v1.SimpleService', method: 'SimpleUnaryRequest' },
  payload,
  metadata
);

GrpcClient API

GrpcClient has public methods to query gRPC server:

class GrpcClient<MetadataValue, Metadata> {
  public invokeUnaryRequest<Request, Response>(
    options: GrpcRequestOptions,
    request: Request,
    metadata?: Record<string, MetadataValue>
  ): Promise<GrpcResponse<Response>>;

  public invokeClientStreamingRequest<Request, Response>(
    options: GrpcRequestOptions,
    metadata?: Record<string, MetadataValue>
  ): ClientStream<Request, Response>;

  public invokeServerStreamingRequest<Request, Response>(
    options: GrpcRequestOptions,
    payload: Request,
    metadata?: Record<string, MetadataValue>
  ): ServerStream<Response>;

  public invokeBidirectionalStreamingRequest<Request, Response>(
    options: GrpcRequestOptions,
    metadata?: Record<string, MetadataValue>
  ): BidirectionalStream<Request, Response>;
}

The first argument in each method defines the query options - service and method name.

interface GrpcRequestOptions {
  service: string;
  method: string;
}

Response Convention

Response type in methods are wrapped with GrpcResponse type.

interface GrpcErrorResponseValue {
  details?: string;
  metadata?: Record<string, unknown>;
}

type GrpcResponseValue = Record<string, unknown>;

interface GrpcResponse<Response extends GrpcResponseValue = GrpcResponseValue> {
  /**
   * Status code of gRPC request
   */
  code: GrpcStatus;

  /**
   * For unary requests - query execution time in milliseconds.
   * For streaming requests - receiving response actual time in utc.
   */
  timestamp: number;

  data: Response | GrpcErrorResponseValue;
}

Unary Request

const response = await client.invokeUnaryRequest(
  { service: 'simple_package.v1.SimpleService', method: 'SimpleUnaryRequest' },
  { id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' }
);

Note
If error occured this method will not through error. You can handle this by checking status code in response.

import { GrpcStatus } from '@getezy/grpc-client';

const response = await client.invokeUnaryRequest(
  { service: 'simple_package.v1.SimpleService', method: 'SimpleUnaryRequest' },
  { id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' }
);

if (response.code !== GrpcStatus.OK) {
  // do something
}

Client-Streaming Request

const stream = client.invokeClientStreamingRequest({
  service: 'simple_package.v1.SimpleService',
  method: 'SimpleClientStreamRequest',
});

stream.on('response', (response) => {});

stream.on('error', (error) => {});

stream.write({ id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' });

stream.end();

// If you want to cancel stream from the client do
stream.cancel()

ClientStream extended from EventEmitter.

Events:

stream.on('response', (response: GrpcResponse<Response>) => {})
Sibscribe on server response.

stream.on('error', (error: GrpcResponse<Response>) => {})
Subscribe on server error.

Methods:

stream.write(payload: Request)
Send payload to the stream.

stream.cancel()
Cancel the stream.

stream.end()
End the stream.

Server-Streaming Request

const stream = client.invokeServerStreamingRequest(
  {
    service: 'simple_package.v1.SimpleService',
    method: 'SimpleServerStreamRequest',
  },
  { id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' },
);

stream.on('response', (response) => {});

stream.on('error', (error) => {});

stream.on('end', () => {});

// If you want to cancel stream from the client do
stream.cancel()

ServerStream extended from EventEmitter.

Events:

stream.on('response', (response: GrpcResponse<Response>) => {})
Sibscribe on server response.

stream.on('error', (error: GrpcResponse<Response>) => {})
Subscribe on server error.

Methods:

stream.cancel()
Cancel the stream.

Bidirectional-Streaming Request

const stream = client.invokeBidirectionalStreamingRequest({
  service: 'simple_package.v1.SimpleService',
  method: 'SimpleBidirectionalStreamRequest',
});

stream.on('response', (response) => {});

stream.on('error', (error) => {});

stream.on('end-server-stream', () => {})

stream.write({ id: '21443e83-d6ab-45b7-9afd-65b2e0ee8957' });

stream.end();

// If you want to cancel stream from the client do
stream.cancel()

BidirectionalStream extended from EventEmitter.

Events:

stream.on('response', (response: GrpcResponse<Response>) => {})
Sibscribe on server response.

stream.on('error', (error: GrpcResponse<Response>) => {})
Subscribe on server error.

stream.on('end-server-stream', () => {})
Subscribe on end server stream.

Methods:

stream.write(payload: Request)
Send payload to the stream.

stream.cancel()
Cancel the stream.

stream.end()
End the client stream.

TLS

Read this article to understand how to configure TLS for gRPC and gRPC-Web server.

There are three connection types:

  • Insecure — all data transmitted without encryption.
  • Server-Side TLS — browser like encryption, where only the server provides TLS certificate to the client.
  • Mutual TLS — most secure, both the server and the client provides their certificates to each other.

Note
Each protocol accepts TLS options. If TLS options are not specified Insecure connection will be used by default.

Insecure

import { GrpcProtocol, GrpcTlsType } from '@getezy/grpc-client';

const protocol = new GrpcProtocol({
  address: '10.10.10.10',
  tls: {
    type: GrpcTlsType.INSECURE,
  },
});

Server-Side TLS

import * as path from 'node:path';
import { GrpcProtocol, GrpcTlsType } from '@getezy/grpc-client';

const protocol = new GrpcProtocol({
  address: '10.10.10.10',
  tls: {
    tls: {
      type: GrpcTlsType.SERVER_SIDE,
      rootCertificatePath: path.join(__dirname, '../certs/ca-cert.pem'),
    },
  },
});

Note
rootCertificatePath - is optional, usually used if your server has self-signed CA

Mutual TLS

import * as path from 'node:path';
import { GrpcProtocol, GrpcTlsType } from '@getezy/grpc-client';

const protocol = new GrpcProtocol({
  address: '10.10.10.10',
  tls: {
    type: GrpcTlsType.MUTUAL,
    rootCertificatePath: path.join(__dirname, '../certs/ca-cert.pem'),
    clientCertificatePath: path.join(__dirname, '../certs/client-cert.pem'),
    clientKeyPath: path.join(__dirname, '../certs/client-key.pem'),
  },
});

Note
rootCertificatePath - is optional, usually used if your server has self-signed CA

Loaders

Loader - is the strategy defines how to load gRPC package definitions.

ProtobufLoader

Uses @grpc/proto-loader for load protobuf definition from the giving path.

new ProtobufLoader(path: string, [options])

import { ProtobufLoader } from '@getezy/grpc-client';
import * as path from 'node:path';

const loader = new ProtobufLoader(
  path.join(__dirname, '../proto/main.proto'),
  {
    defaults: false,
  }
);

await loader.load();

Refer to @grpc/proto-loader documentation to see available options.

Default options are:

{
  // Preserve field names. The default
  // is to change them to camel case.
  keepCase: true,

  // Set default values on output objects.
  // Defaults to false.
  defaults: true,

  // A list of search paths for imported .proto files.
  includeDirs: [],

  // The type to use to represent long values.
  // Defaults to a Long object type.
  longs: String,
}

ReflectionLoader

Loader by reflection API is coming soon.

CustomLoader

You can write custom loader implementation by extending AbstractLoader class imported from @getezy/grpc-client.

import { AbstractLoader } from '@getezy/grpc-client';

class CustomLoader extends AbstractLoader {
  public async load(): Promise<void> {
    // custom loader implementation
  }
}

Protocols

Protocol - is the strategy defines how to make queries to gRPC server.

GrpcProtocol

Uses @grpc/grpc-js.

new GrpcProtocol(options: GrpcProtocolOptions)

import { GrpcProtocol, GrpcTlsType } from '@getezy/grpc-client';

const protocol = new GrpcProtocol({
  address: '10.10.10.10',
  tls: { type: GrpcTlsType.INSECURE },
  channelOptions: { sslTargetNameOverride: 'test' },
});

GrpcWebProtocol

Uses @improbable-eng/grpc-web.

Note
Official gRPC-Web implementation has problems with server-streaming responses. Read more here.

Warning
gRPC-Web protocol supports only unary and server-streaming requests, follow the streaming roadmap here. When you will try to call client or bidirectional streaming request with this protocol you will get the error.

new GrpcWebProtocol(options: AbstractProtocolOptions)

import { GrpcWebProtocol, GrpcTlsType } from '@getezy/grpc-client';

const protocol = new GrpcWebProtocol({
  address: '10.10.10.10',
  tls: { type: GrpcTlsType.INSECURE },
});

Custom protocol

You can write custom protocol implementation by extending AbstractProtocol class imported from @getezy/grpc-client.

import { AbstractProtocol } from '@getezy/grpc-client';

class CustomProtocol extends AbstractProtocol<MetadataValue, Metadata> {
  // custom protocol implementation
}

License

Mozilla Public License Version 2.0