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.
- 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
RequestAPI for collecting metadata and status.
$ npm install @eeston/grpc-caller
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)
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);
});
// ... write stuff to callIf 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));
// ... write stuff to callThis 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();
// ... write stuff to call
return res;
}
const res = await writeStuff();
console.log(res);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.
// the 2nd parameter will automatically be converted to gRPC Metadata and
// included in the request
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);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.
const req = new client.Request("sayHello", { name: "Bob" }) // call method name and argument
.withMetadata({ requestId: "bar-123" }) // call request metadata
.withResponseMetadata(true) // we want to collect response metadata
.withResponseStatus(true) // we want to collect the response status
.withRetry(5); // retry options
const res = await req.exec();
// res is an instance of our `Response`
// we can also call exec() using a callback
console.log(res.response); // the actual response data { message: 'Hello Bob!' }
console.log(res.metadata); // the response metadata
console.log(res.status); // the response status
console.log(res.call); // the internal gRPC callIn 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") // the call method name
.withMetadata({ requestId: "bar-123" }) // the call request metadata
.withResponseMetadata(true) // we want to collect response metadata
.withResponseStatus(true); // we want to collect the response status
const { call, res: resPromise } = req.exec();
// ... write data to call
const res = await resPromise; // res is our `Response`
console.log(res.response); // the actual response data
console.log(res.metadata); // the response metadata
console.log(res.status); // the response status
console.log(res.call); // the internal gRPC callA Request class that encapsulates the request of a call.
Kind: global class
- Request
- new Request(methodName, param)
- .withGrpcOptions(opts) ⇒
Object - .withMetadata(opts) ⇒
Object - .withRetry(retry) ⇒
Object - .withResponseMetadata(value) ⇒
Object - .withResponseStatus(value) ⇒
Object - .exec(fn) ⇒
Promise|Object
Creates a Request instance.
| Param | Type | Description |
|---|---|---|
| methodName | String |
the method name. |
| param | * |
the call argument in case of UNARY calls. |
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. |
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. |
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. |
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. |
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. |
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 |
A Response class that encapsulates the response of a call using the Request API.
Kind: global class
The response's gRPC call.
Kind: instance property of Response
The actual response data from the call.
Kind: instance property of Response
The response metadata.
Kind: instance property of Response
The response status metadata.
Kind: instance property of Response
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 = {
// ... proto-loader load options
};
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' }
})
// Now every call with that client will result
// in invoking the interceptor and sending the default metadataUtility helper function to create Metadata object from plain Javascript object.
See grpc-create-metadata module.
Kind: static property of caller
Utility function that can be used to wrap an already constructed client instance.
Kind: static property of caller
Apache-2.0