An open API service indexing awesome lists of open source software.

https://github.com/leonardoraele/json-rpc-dual-engine

A Javascript JSON-RPC-2.0 transport protocol agnostic client and server engine.
https://github.com/leonardoraele/json-rpc-dual-engine

client http https json json-rpc json-rpc-client json-rpc-engine json-rpc-server json-rpc2 rpc server server-engines socket websocket

Last synced: 6 months ago
JSON representation

A Javascript JSON-RPC-2.0 transport protocol agnostic client and server engine.

Awesome Lists containing this project

README

          

# json-rpc-dual-engine
![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/leonardoraele/json-rpc-dual-engine/Test/master)
![NPM](https://img.shields.io/npm/l/json-rpc-dual-engine)
![node-current](https://img.shields.io/node/v/json-rpc-dual-engine)
![npm](https://img.shields.io/npm/v/json-rpc-dual-engine)
![GitHub last commit](https://img.shields.io/github/last-commit/leonardoraele/json-rpc-dual-engine)
![npm](https://img.shields.io/npm/dw/json-rpc-dual-engine)

A transport agnostic implementation of the [JSON-RPC-2.0 spec].

This package includes a client and a server.
You can import either separately without increasing the size of your final build, if you don't need both.

[JSON-RPC-2.0 spec]: https://www.jsonrpc.org/specification

## Install

```bash
npm install json-rpc-dual-engine
```

## Usage

### Server
Create the server with an object that implements the methods to be exposed to the client:

```js
import { JsonRpcServer } from 'json-rpc-dual-engine/server';

const api = {
multiply(a, b) {
return a * b;
},
ping() {
return 'pong';
},
};

const server = new JsonRpcServer({ api });
```

Register a `transport` callback to receive the json-rpc responses generated by the server:

```js
// `transport` will be called whenever the server generates a response.
// It's your job is to send it to the client somehow.
server.transport = response => console.log(response);
```

Then use the `accept` method to deliver incoming remote method calls to the server.
The server validates the json-rpc message call, calls the appropriate registered method,
and generate the appropriate json-rpc response based on the return of the registered handler.

```js
// It's your job to receive the request from the client somehow.
const request = '{"jsonrpc":"2.0","method":"multiply","params":[7,11],"id":"1"}';

server.accept(request);
// Output: '{"jsonrpc":"2.0","result":77,"id":"1"}'
```

### Client
Create the client:

```js
import { JsonRpcClient } from 'json-rpc-dual-engine/client';

const client = new JsonRpcClient();
```

Register a `transport` callack to send requests made by the client to the server.

```js
// It's your job to send the requests to the server somehow.
client.transport = request => console.log(request);

client.sendRequest('multiply', [7, 11]);
// Output: '{"jsonrpc":"2.0","method":"multiply","params":[7,11],"id":"1"}'

client.sendNotification('ping'); // no return
// Output: '{"jsonrpc":"2.0","method":"ping"}'

// Or use the proxy object:
client.remote.multiply(7, 11);
client.remote.ping();
```

Use the `accept` method to deliver incoming server responses to the client to resolve request promises.

```js
// Using setTimeout to simulate a future incoming message from the server
setTimeout(100, () => {
const response = '{"jsonrpc":"2.0","result":77,"id":"2"}'; // Gets a response from the server somehow
client.accept(response);
});

const result = await client.request('multiply', [7, 11]);

console.log(result); // Output: 77
```

Or using the proxy object:

```js
const remote = client.remote;

const result = await remote.multiply(7, 11);

console.log(result); // Output: 77
```

### Server and Client

The `JsonRpcDualEngine` class includes both a client and a server in it.
It's useful in cases where you need bidirectional communication.
The `accept()` method of the dual engine accepts both requests and responses.

```js
import { JsonRpcDualEngine } from 'json-rpc-dual-engine';

const engine1 = new JsonRpcDualEngine({
api: {
getId() { return '1'; }
}
});

const engine2 = new JsonRpcDualEngine({
api: {
getId() { return '2'; }
}
});

engine1.onmessage = message => engine2.accept(message);
engine2.onmessage = message => engine1.accept(message);

console.log(await engine1.sendRequest('getId')); // Output: '2'
console.log(await engine2.sendRequest('getId')); // Output: '1'
```

### WebSocket Example

On the server side:

```js
import { JsonRpcServer } from 'json-rpc-dual-engine/server';
import { WebSocketServer } from 'ws';

const wss = new WebSocketServer({ port: 8080 });
const engine = JsonRpcServer({
api: {
multiply(a, b) {
return a * b;
}
}
});

wss.on('connection', ws => {
ws.on('message', request => engine.accept(request)); // Messages from the client are handled by the engine
engine.transport = response => ws.send(response); // Responses are sent to the client via websocket
});
```

On the client side:

```js
import { JsonRpcClient } from 'json-rpc-dual-engine/client';
import WebSocket from 'ws';

const websocket = new WebSocket('ws://remote.example');
const engine = new JsonRpcClient();

engine.transport = request => websocket.send(request); // Requests are sent to the server via websocket
websocket.on('message', response => engine.accept(response)); // Responses from the server are handled by the engine

// Waits for connection before sending a message
await new Promise((resolve, reject) => {
websocket.onopen = resolve;
websocket.onerror = reject;
});

// Sends a json-rpc request through webscoket to the remote server and waits for the response
const result = await engine.remote.multiply(7, 11);

console.log(result); // Output: 77
```

## Development Environment

#### Install Deps

npm install

#### Test

npm test

#### Coverage

npm run coverage

## LICENSE

[MIT](./LICENSE.md)