grpc-web-rx
Advanced tools
Comparing version
{ | ||
"name": "grpc-web-rx", | ||
"version": "0.1.0", | ||
"version": "0.1.1", | ||
"homepage": "https://wisetime.com", | ||
@@ -5,0 +5,0 @@ "main": "src/index.ts", |
126
README.md
# gRPC-Web-Rx | ||
gRPC-Web-Rx is a TypeScript library that integrates [gRPC-Web](https://github.com/grpc/grpc-web) with [RxJS](https://github.com/ReactiveX/rxjs). | ||
gRPC-Web-Rx is a TypeScript library that integrates [gRPC-Web](https://github.com/grpc/grpc-web) with [RxJS](https://github.com/ReactiveX/rxjs). gRPC-Web-Rx provides a convenience `from` operator that you can use to wrap your gRPC call to obtain an `Observable` of the response. Currently unary and server streaming RPCs are supported. | ||
gRPC Call Type | Input and Output Types | ||
--- | --- | ||
Unary | `Request => Observable<Response>` | ||
Server streaming | `Request => Observable<Response>` | ||
Client streaming | Not yet supported by gRPC-Web | ||
Bidirectional streaming | Not yet supported by gRPC-Web | ||
## Usage | ||
gRPC-Web-Rx provides a `from` operator that creates an `Observable` from a gRPC call. The library also provides a `retry` operator for retrying failed calls. | ||
You can install the `grpc-web-rx` module via [npm](https://github.com/npm/cli): | ||
```typescript | ||
const grpcClient = new FooClient("http://localhost:8081"); | ||
```text | ||
npm i grpc-web-rx | ||
``` | ||
// from returns an Observable | ||
from<FooResponse>(() => grpcClient.foo(new FooRequest(), {})) | ||
.subscribe({ | ||
next: data => console.log(data.getBar()), | ||
error: error => console.log(error), | ||
complete: () => console.log("complete") | ||
}) | ||
Let's look at a hypothetical Todo service, defined using [Protocol Buffers](https://developers.google.com/protocol-buffers) as: | ||
// using retry with custom retry policy | ||
// add exponential backoff to your beforeRetry callback by using the addExponentialDelay convenience function | ||
const withDelay = addExponentialDelay<void>(2000, 60_000) | ||
const beforeRetry = withDelay(of(undefined)) | ||
const retryPolicy = { | ||
shouldRetry: (error: Grpc.Error) => error.code == Grpc.StatusCode.PERMISSION_DENIED, | ||
maxRetries: 2, | ||
beforeRetry: (attempt: number) => of("something that resolves"), | ||
```protobuf | ||
syntax = "proto3"; | ||
package wisetime.todo.v1; | ||
service TodoService { | ||
// Use this unary RPC to create todo items. | ||
rpc CreateTodo(CreateTodoRequest) returns (Todo); | ||
// Subscribe to this server streaming RPC to receive todo list updates. | ||
rpc WatchTodos(WatchTodosRequest) returns (stream TodoList); | ||
} | ||
from<FooResponse>(() => grpcClient.foo(new FooRequest(), {})) | ||
.pipe(retry(retryPolicy)) | ||
message Todo { | ||
string id = 1; | ||
string title = 2; | ||
bool completed = 3; | ||
} | ||
message CreateTodoRequest { | ||
string title = 1; | ||
} | ||
message WatchTodosRequest {} | ||
message TodoList { | ||
repeated Todo todos = 1; | ||
} | ||
``` | ||
In order to use gRPC-Web, we need to generate the client library from using [protoc](https://github.com/protocolbuffers/protobuf#protocol-compiler-installation) and the [gRPC-Web protoc plugin](https://github.com/grpc/grpc-web#code-generator-plugin): | ||
```text | ||
protoc -I=src/protobuf src/protobuf/todo.proto \ | ||
--js_out=import_style=commonjs,binary:src/generated \ | ||
--grpc-web_out=import_style=typescript,mode=grpcwebtext:src/generated | ||
``` | ||
### The `from` Operator | ||
The `from` operator executes a gRPC call and provides an `Observable` of the response. | ||
```typescript | ||
import { from } from "grpc-web-rx" | ||
import { CreateTodoRequest, WatchTodoRequest } from "./generated/todo_pb" | ||
import { TodoServiceClient } from "./generated/TodoServiceClientPb" | ||
const client = new TodoServiceClient("http://localhost:8080") | ||
// An example unary call. | ||
from(() => client.createTodo(new CreateTodoRequest().setTitle("Buy milk"))) | ||
.subscribe( | ||
response => console.log(`Todo created with ID: ${response.id}`), | ||
error => console.error(`Received error status code: ${error.code}`) | ||
) | ||
// An example server streaming call: Subscribing to an update stream. | ||
from(() => client.watchTodos(new WatchTodosRequest())) | ||
.subscribe({ | ||
next: data => console.log(data.getBar()), | ||
error: error => console.log(error), | ||
complete: () => console.log("complete") | ||
next: todos => console.log(`Received updated todo list: ${todos}`), | ||
error: error => console.error(`Received error status code: ${error.code}`) | ||
complete: () => console.log("Notification stream has ended") | ||
}) | ||
``` | ||
// alternatively you can use the pre-configured retry policies | ||
.pipe(retry(never)) | ||
### Automatic Retries | ||
.pipe(retry(responseNotOk)) // only retries if response status code != 200 | ||
gRPC-Web-Rx also provides a `retry` operator for retrying calls that fail with a non-OK [gRPC Status](https://github.com/grpc/grpc/blob/master/doc/statuscodes.md). | ||
.pipe(retry(retryAfter(1000))) // retries requests with exponential backoff starting at 1 second | ||
``` | ||
In the following example, we configure a `RetryPolicy` that will retry calls that fail with status code `PERMISSION_DENIED`. The call is retried up to 3 times with an initial delay of 200ms. The delay increases exponentially for each subsequent attempt. In this example, the `refreshIdToken()` function is called before each attempt. | ||
## Limitations | ||
```typescript | ||
import Grpc from "grpc-web" | ||
import { from, retry, responseNotOk, addExponentialDelay } from "grpc-web-rx" | ||
import { CreateTodoRequest } from "./generated/todo_pb" | ||
- This library only supports unary and server streaming gRPC calls. | ||
const policy = responseNotOk( | ||
error => error.code == Grpc.StatusCode.PERMISSION_DENIED, | ||
maxRetries = 3, | ||
beforeRetry: addExponentialDelay(200)(refreshIdToken()) | ||
) | ||
from(() => client.createTodo(new CreateTodoRequest().setTitle("Very important task!"))) | ||
.pipe(retry(policy)) | ||
.subscribe( | ||
response => console.log(`Todo created with ID: ${response.id}`), | ||
error => console.error(`Received error status code: ${error.code}`) | ||
) | ||
``` | ||
## Contributing | ||
You will need to install the following to work on gRPC-Web-Rx: | ||
You will need to install the following tools to work on gRPC-Web-Rx: | ||
@@ -65,2 +126,1 @@ - [protoc](https://github.com/protocolbuffers/protobuf/releases) | ||
This starts a local gRPC node server together with an Envoy proxy (via Docker) where the tests will be run against. | ||
135358
4.76%36
5.88%2604
4.45%126
90.91%