Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Request API #11

Merged
merged 17 commits into from
May 7, 2018
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ jspm_packages
.node_repl_history

_book
*.orig
218 changes: 215 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ An improved [gRPC](http://www.grpc.io) client.

#### Features

* Promisifies request / response calls if no callback is supplied
* 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

Expand All @@ -22,7 +24,7 @@ $ npm install grpc-caller

## Overview

#### Improved request / response calls
#### Improved unary calls

Works as standard gRPC client:

Expand All @@ -35,7 +37,7 @@ client.sayHello({ name: 'Bob' }, (err, res) => {
})
```

For request / response calls, also promisified if callback is not provided:
For unary calls, also promisified if callback is not provided:

```js
client.sayHello({ name: 'Bob' })
Expand All @@ -49,6 +51,13 @@ const res = await client.sayHello({ name: 'Bob' })
console.log(res)
```

For Unary calls we expose `retry` option identical to [async.retry](http://caolan.github.io/async/docs.html#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
Expand Down Expand Up @@ -120,8 +129,199 @@ 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

```js
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 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.

```js

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 call
```

## API Reference

<a name="Request"></a>

### Request
A Request class that encapsulates the request of a call.

**Kind**: global class

* [Request](#Request)
* [new Request(methodName, param)](#new_Request_new)
* [.withGrpcOptions(opts)](#Request+withGrpcOptions) ⇒ <code>Object</code>
* [.withMetadata(opts)](#Request+withMetadata) ⇒ <code>Object</code>
* [.withRetry(retry)](#Request+withRetry) ⇒ <code>Object</code>
* [.withResponseMetadata(value)](#Request+withResponseMetadata) ⇒ <code>Object</code>
* [.withResponseStatus(value)](#Request+withResponseStatus) ⇒ <code>Object</code>
* [.exec(fn)](#Request+exec) ⇒ <code>Promise</code> \| <code>Object</code>

<a name="new_Request_new"></a>

#### new Request(methodName, param)
Creates a Request instance.


| Param | Type | Description |
| --- | --- | --- |
| methodName | <code>String</code> | the method name. |
| param | <code>\*</code> | the call argument in case of `UNARY` calls. |

<a name="Request+withGrpcOptions"></a>

#### request.withGrpcOptions(opts) ⇒ <code>Object</code>
Create a request with call options.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Object</code> - the request instance.

| Param | Type | Description |
| --- | --- | --- |
| opts | <code>Object</code> | The gRPC call options. |

<a name="Request+withMetadata"></a>

#### request.withMetadata(opts) ⇒ <code>Object</code>
Create a request with call metadata.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Object</code> - the request instance.

| Param | Type | Description |
| --- | --- | --- |
| opts | <code>Object</code> | The gRPC call metadata. Can either be a plain object or an instance of `grpc.Metadata`. |

<a name="Request+withRetry"></a>

#### request.withRetry(retry) ⇒ <code>Object</code>
Create a request with retry options.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Object</code> - the request instance.

| Param | Type | Description |
| --- | --- | --- |
| retry | <code>Number</code> \| <code>Object</code> | The retry options. Identical to `async.retry`. |

<a name="Request+withResponseMetadata"></a>

#### request.withResponseMetadata(value) ⇒ <code>Object</code>
Create a request indicating whether we want to collect the response metadata.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Object</code> - the request instance.

| Param | Type | Description |
| --- | --- | --- |
| value | <code>Boolean</code> | `true` to collect the response metadata. Default `false`. |

<a name="Request+withResponseStatus"></a>

#### request.withResponseStatus(value) ⇒ <code>Object</code>
Create a request indicating whether we want to collect the response status metadata.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Object</code> - the request instance.

| Param | Type | Description |
| --- | --- | --- |
| value | <code>Boolean</code> | `true` to collect the response status metadata. Default `false`. |

<a name="Request+exec"></a>

#### request.exec(fn) ⇒ <code>Promise</code> \| <code>Object</code>
Execute the request.

**Kind**: instance method of [<code>Request</code>](#Request)
**Returns**: <code>Promise</code> \| <code>Object</code> - 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 | <code>function</code> | Optional callback |

<a name="Response"></a>

### Response
A Response class that encapsulates the response of a call using the `Request` API.

**Kind**: global class

* [Response](#Response)
* [.call](#Response+call) : <code>Object</code>
* [.response](#Response+response) : <code>Object</code>
* [.metadata](#Response+metadata) : <code>Object</code>
* [.status](#Response+status) : <code>Object</code>

<a name="Response+call"></a>

#### response.call : <code>Object</code>
The response's gRPC call.

**Kind**: instance property of [<code>Response</code>](#Response)
<a name="Response+response"></a>

#### response.response : <code>Object</code>
The actual response data from the call.

**Kind**: instance property of [<code>Response</code>](#Response)
<a name="Response+metadata"></a>

#### response.metadata : <code>Object</code>
The response metadata.

**Kind**: instance property of [<code>Response</code>](#Response)
<a name="Response+status"></a>

#### response.status : <code>Object</code>
The response status metadata.

**Kind**: instance property of [<code>Response</code>](#Response)
<a name="caller"></a>

### caller(host, proto, name, options) ⇒ <code>Object</code>
Expand All @@ -135,6 +335,7 @@ Create client isntance.
| proto | <code>String</code> \| <code>Object</code> | Path to the protocol buffer definition file or Object specifying <code>root</code> directory and <code>file</code> to load or the static client constructor object itself |
| name | <code>String</code> | In case of proto path the name of the service as defined in the proto definition. |
| options | <code>Object</code> | Options to be passed to the gRPC client constructor |
| options.retry | <code>Object</code> | 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. |

**Example** *(Create client dynamically)*
```js
Expand All @@ -150,12 +351,23 @@ const client = caller('localhost:50051', { root, file }, 'Greeter')
const services = require('./static/helloworld_grpc_pb')
const client = caller('localhost:50051', services.GreeterClient)
```

* [caller(host, proto, name, options)](#caller) ⇒ <code>Object</code>
* [.metadata](#caller.metadata)
* [.wrap](#caller.wrap)

<a name="caller.metadata"></a>

#### caller.metadata
Utility helper function to create <code>Metadata</code> object from plain Javascript object.
See <code>grpc-create-metadata</code> module.

**Kind**: static property of [<code>caller</code>](#caller)
<a name="caller.wrap"></a>

#### caller.wrap
Utility function that can be used to wrap an already constructed client instance.

**Kind**: static property of [<code>caller</code>](#caller)
## License

Expand Down
Loading