grpc-caller
An improved gRPC client.
This forked repository aims to provide a @grpc/grpc-js
compatable version of grpc-caller. The original repository relies on grpc
which is no longer supported.
Features
- Promisifies request / response (Unary) calls if no callback is supplied
- Promisifies request stream / response calls if no callback is supplied
- Automatically converts plain javascript object to metadata in calls.
- Adds optional retry functionality to request / response (Unary) calls.
- Exposes expanded
Request
API for collecting metadata and status.
Installation
$ npm install @eeston/grpc-caller
Overview
Improved unary calls
Works as standard gRPC client:
const caller = require("grpc-caller");
const PROTO_PATH = path.resolve(__dirname, "./protos/helloworld.proto");
const client = caller("0.0.0.0:50051", PROTO_PATH, "Greeter");
client.sayHello({ name: "Bob" }, (err, res) => {
console.log(res);
});
For unary calls, also promisified if callback is not provided:
client.sayHello({ name: "Bob" }).then((res) => console.log(res));
Which means means you can use is with async / await
const res = await client.sayHello({ name: "Bob" });
console.log(res);
For Unary calls we expose retry
option identical to async.retry.
const res = await client.sayHello({ name: 'Bob' }, {}, { retry: 3 })
console.log(res)
Improved request stream / response calls
Lets say we have a remote call writeStuff
that accepts a stream of messages
and returns some result based on processing of the stream input.
Works as standard gRPC client:
const call = client.writeStuff((err, res) => {
if (err) console.error(err);
console.log(res);
});
If no callback is provided we promisify the call such that it returns an object
with two properties call
and res
such that:
call
- the standard stream to write to as returned normally by grpcres
- a promise that's resolved / rejected when the call is finished, in place of the callback.
Using destructuring we can do something like:
const { call, res } = client.writeStuff();
res.then((res) => console.log(res)).catch((err) => console.error(err));
This means we can abstract the whole operation into a nicer promise returning
async function to use with async / await
async function writeStuff() {
const { call, res } = client.writeStuff();
return res;
}
const res = await writeStuff();
console.log(res);
Automatic Metadata
creation
All standard gRPC client calls accept Metadata
as first or second parameter (depending on the call type). However one has to
manually create the Metadata object. This module uses
grpc-create-metadata
to automatically create Metadata if plain Javascript object is passed in.
const res = await client.sayHello(
{ name: "Bob" },
{ requestid: "my-request-id-123" }
);
console.log(res);
We can still pass an actual Metadata
object and it will be used as is:
const meta = new grpc.Metadata();
meta.add("requestid", "my-request-id-123");
const res = await client.sayHello({ name: "Bob" }, meta);
console.log(res);
Request API
In addition to simple API above, the library provides a more detailed "Request"
API that can
be used to control the call details. The API can only be used for Unary and
request streaming calls.
Unary calls
const req = new client.Request("sayHello", { name: "Bob" })
.withMetadata({ requestId: "bar-123" })
.withResponseMetadata(true)
.withResponseStatus(true)
.withRetry(5);
const res = await req.exec();
console.log(res.response);
console.log(res.metadata);
console.log(res.status);
console.log(res.call);
Request streaming calls
In case of request streaming calls if exec()
is called with a callback the gRPC call
stream is returned.
If no callback is provided an object is returned with call
property being the call stream and res
property being a Promise fulfilled when the call is completed. There is no retry
option for
request streaming calls.
const req = new client.Request("writeStuff")
.withMetadata({ requestId: "bar-123" })
.withResponseMetadata(true)
.withResponseStatus(true);
const { call, res: resPromise } = req.exec();
const res = await resPromise;
console.log(res.response);
console.log(res.metadata);
console.log(res.status);
console.log(res.call);
API Reference
Request
A Request class that encapsulates the request of a call.
Kind: global class
new Request(methodName, param)
Creates a Request instance.
Param | Type | Description |
---|
methodName | String | the method name. |
param | * | the call argument in case of UNARY calls. |
request.withGrpcOptions(opts) ⇒ Object
Create a request with call options.
Kind: instance method of Request
Returns: Object
- the request instance.
Param | Type | Description |
---|
opts | Object | The gRPC call options. |
request.withMetadata(opts) ⇒ Object
Create a request with call metadata.
Kind: instance method of Request
Returns: Object
- the request instance.
Param | Type | Description |
---|
opts | Object | The gRPC call metadata. Can either be a plain object or an instance of grpc.Metadata . |
request.withRetry(retry) ⇒ Object
Create a request with retry options.
Kind: instance method of Request
Returns: Object
- the request instance.
Param | Type | Description |
---|
retry | Number | Object | The retry options. Identical to async.retry . |
request.withResponseMetadata(value) ⇒ Object
Create a request indicating whether we want to collect the response metadata.
Kind: instance method of Request
Returns: Object
- the request instance.
Param | Type | Description |
---|
value | Boolean | true to collect the response metadata. Default false . |
request.withResponseStatus(value) ⇒ Object
Create a request indicating whether we want to collect the response status metadata.
Kind: instance method of Request
Returns: Object
- the request instance.
Param | Type | Description |
---|
value | Boolean | true to collect the response status metadata. Default false . |
request.exec(fn) ⇒ Promise
| Object
Execute the request.
Kind: instance method of Request
Returns: Promise
| Object
- If no callback is provided in case of UNARY
call a Promise is returned.
If no callback is provided in case of REQUEST_STREAMING
call an object is
returned with call
property being the call stream and res
property being a Promise fulfilled when the call is completed.
Param | Type | Description |
---|
fn | function | Optional callback |
Response
A Response class that encapsulates the response of a call using the Request
API.
Kind: global class
response.call : Object
The response's gRPC call.
Kind: instance property of Response
response.response : Object
The actual response data from the call.
Kind: instance property of Response
response.metadata : Object
The response metadata.
Kind: instance property of Response
response.status : Object
The response status metadata.
Kind: instance property of Response
caller(host, proto, name, credentials, options, defaults) ⇒ Object
Create client isntance.
Kind: global function
Param | Type | Description |
---|
host | String | The host to connect to |
proto | String | Object | Path to the protocol buffer definition file or Object specifying file to load and load options for proto loader. |
name | String | In case of proto path the name of the service as defined in the proto definition. |
credentials | Object | The credentials to use to connect. Defaults to grpc.credentials.createInsecure() |
options | Object | Options to be passed to the gRPC client constructor |
options.retry | Object | In addition to gRPC client constructor options, we accept a retry option. The retry option is identical to async.retry and is passed as is to it. This is used only for UNARY calls to add automatic retry capability. |
defaults | Object | Metadata and Options that will be passed to every Request |
Example (Create client dynamically)
const PROTO_PATH = path.resolve(__dirname, "./protos/helloworld.proto");
const client = caller("localhost:50051", PROTO_PATH, "Greeter");
Example (With options)
const file = path.join(__dirname, "helloworld.proto");
const load = {
};
const client = caller("localhost:50051", { file, load }, "Greeter");
Example (Create a static client)
const services = require("./static/helloworld_grpc_pb");
const client = caller("localhost:50051", services.GreeterClient);
Example (Pass Options, Default Metadata and Interceptor options)
const metadata = { node_id: process.env.CLUSTER_NODE_ID };
const credentials = grpc.credentials.createInsecure()
const options = {
interceptors = [ bestInterceptorEver ]
}
const client = caller('localhost:50051', PROTO_PATH, 'Greeter', credentials, options, {
metadata: { foo: 'bar' }
})
caller.metadata
Utility helper function to create Metadata
object from plain Javascript object.
See grpc-create-metadata
module.
Kind: static property of caller
caller.wrap
Utility function that can be used to wrap an already constructed client instance.
Kind: static property of caller
License
Apache-2.0