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

https://github.com/maxzinchenko/redux-ws-middleware

This package makes web socket management much easier with redux.
https://github.com/maxzinchenko/redux-ws-middleware

middleware redux redux-middleware redux-ws-middleware websocket

Last synced: about 1 year ago
JSON representation

This package makes web socket management much easier with redux.

Awesome Lists containing this project

README

          

# Redux WebSocket Middleware

This package makes web socket management much easier with redux.

The package is built over the WebSocket constructor from browser API.


npm version


size


size


npm downloads

---

# Examples

- [Single socket](https://github.com/maxzinchenko/redux-ws-middleware/tree/master/examples/single-socket)

---

# Structure

- [Installation](#installation)
- [Options](#options)
- [url](#url)
- [actionTypes](#actionTypes)
- [completedActionTypes](#completedActionTypes)
- [onMessage](#onMessage)
- [autoConnect](#autoConnect)
- [protocols](#protocols)
- [shouldReconnect](#shouldReconnect)
- [shouldOpen](#shouldOpen)
- [shouldClose](#shouldClose)
- [reconnectionIntervals](#reconnectionInterval)
- [serialize](#serialize)
- [deserialize](#deserialize)
- [debug](#debug)
- [Usage](#usage)
- [Connecting](#connecting)
- [Disconnecting](#disconnecting)
- [Sending data](#sending-data)
- [MiddlewareOptions declaration](#middlewareoptions-declaration)
- [Passing own types to MiddlewareOptions type](#passing-own-types-to-middlewareoptions-type)

---

## Installation

```
# using npm
npm install redux-ws-middleware

# using yarn
yarn add redux-ws-middleware
```

---

## Options

| Name | Required | Type | Default |
| ---------------------------------------------- | -------- | --------------------------------------------------- | ----------- |
| [url](#url) | Yes | `string` | - |
| [actionTypes](#actionTypes) | Yes | `Array` | - |
| [completedActionTypes](#completedActionTypes) | Yes | `Array` | - |
| [onMessage](#onMessage) | Yes | `(res: Res, dispatch: Dispatch) => void` | - |
| [autoConnect](#autoConnect) | No | `boolean` | `true` |
| [protocols](#protocols) | No | `string OR string[]` | - |
| [shouldReconnect](#shouldReconnect) | No | `((event: CloseEvent) => boolean) OR boolean` | `true` |
| [reconnectionIntervals](#reconnectionInterval) | No | `number OR number[]` | `1000` |
| [shouldOpen](#shouldReconnect) | No | `((req: Req) => boolean) OR boolean` | `false` |
| [shouldClose](#shouldReconnect) | No | `((res: DRes) => boolean) OR boolean` | `false` |
| [serialize](#serialize) | No | `(req: Req) => SReq` | - |
| [deserialize](#deserialize) | No | `(res: Res) => DRes` | - |
| [debug](#debug) | No | `boolean` | - |

--------

## url

Required*

Type: `string`

Url for the WebSocket constructor.

```ts
url: 'ws://localhost:3000'
```

```ts
url: 'wss://example.com'
```

## actionTypes

Required*

Type: `[RegExp | string, RegExp | string, RegExp | string]`

WARNING: Sequence is important!

Types that you are able to manage the socket with.

You can have socket dispatching any of them.

The first element should be the `SEND` action type.

Second - `CONNECT` type.

Third - `DISCONNECT` type.

IMPORTANT: Do not use `/g` at the end of RegExp!

```ts
actionTypes: ['SEND', 'CONNECT', 'DISCONNECT']
```

```ts
actionTypes: [new RegExp(/_REQUEST$/), 'CONNECT', 'DISCONNECT']
```

If you don't need these: `CONNECT`, `DISCONNECT` so just don't send them.

```ts
actionTypes: ['SEND', 'CONNECT']
```

```ts
actionTypes: ['SEND']
```

```ts
actionTypes: [new RegExp(/_REQUEST$/)]
```

## completedActionTypes

Required*

Type: `[string, string]`

WARNING: Sequence is important!

Types that you receive back on actions.

```ts
completedActionTypes: ['CONNECTED', 'DISCONNECTED']
```

## onMessage

Required*

Type: `(res: Res, dispatch: Dispatch) => void`

The callback gets called with deserialized data already, if you put deserialize function into options, or with a normal data if you don't. And with a `dispatch` so you can manage your store.

*(this is just an example of the `onMessage` handler)

```ts
onMessage: (data, dispatch) => {
switch (data.method) {
case 'posts':
if (data.error) {
dispatch(postsActions.getPostsRejected(data.error));
} else {
dispatch(postsActions.getPostsFulfilled(data.result));
}
break;

...

default:
break;
}
}
```

## autoConnect

Type: `boolean` - (`true` by default)

When `true` you don't need to send anything else to connect it.

When `false` you need to dispatch the connect action with a type `actionTypes[1]`.

```ts
autoConnect: false
```

## debug

Type: `boolean`

When `true` the package shows additional logs.

```ts
debug: ture
```

## protocols

Type: `string | string[]`

Protocols for the WebSocket constructor.

```ts
protocols: 'some protocol'
```

```ts
protocols: ['some protocol']
```

## shouldReconnect

Type: `((event: CloseEvent) => boolean) | boolean` - (`true` by default)

When `true` the socket tries to reconnect if `event.code !== 1005`.

When predicate is passed you are able to decide if the socket needs to be reconnected.

```ts
shouldReconnect: false
```

## reconnectionInterval

Type: `number | number[]` - (`1000` by default)

In milliseconds.

When array each new connection uses the next number from the array for a timeout to avoid DDOSing a server.

```ts
reconnectionInterval: 1000
```

When reconnection count reaches the last array element it uses it each the next time.

When the socket connects back the next reconnection loop will start from the `0` index.

```ts
reconnectionInterval: [0, 1000, 2000, 3000, 4000, 5000, 10000]
```

## shouldOpen

Type: `((req: Req) => boolean) | boolean` - (`false` by default)
Req is a template of the generic MiddlewareOptions type

When `true` the socket opens on any `send` action if connection is closed`.

When predicate is passed you are able to decide if socket needs to be open.

```ts
shouldOpen: true
```

When predicate is passed you are able to decide when socket needs to be open.

```ts
shouldOpen: (req: SomeReq) => req.method === 'load_session'
```

## shouldClose

Type: `((res: DRes) => boolean) | boolean` - (`false` by default)

`DRes` is a templates of the generic `MiddlewareOptions` type

When `true` the socket closes connection after each response from the server.

When predicate is passed you are able to decide when the socket needs to be closed.

```ts
shouldClose: true
```

```ts
shouldClose: (res: SomeDeserializedRes) => res.method === 'logout'
```

## serialize

Type: `(req: Req) => SReq`

`Req` and `SReq` are templates of the generic `MiddlewareOptions` type

The format function gets called to prepare the data to get submitted to the server. For example, `camelCase` to `snake_case` conversion.

```ts
serialize: req => {
return {
...req,
time: Date.now()
}
}
```

## deserialize

Type: `(res: Res) => DRes`

`Res` and `DRes` are templates of the generic `MiddlewareOptions` type

The format function gets called to prepare the message to get submitted to the `onMessage` callback. For example, `snake_case` to `camelCase` conversion.

```ts
deserialize: res => {
return res.data
}
```

---

## Usage

### Connecting
```ts
const SOCKET_SEND = 'SCOKET_SEND';
const SOCKET_CONNECT = 'SOCKET_CONNECT';
const SOCKET_DISCONNECT = 'SOCKET_DISCONNECT';

const otpions = {
...
actionTypes: [SOCKET_SEND, SOCKET_CONNECT, SOCKET_DISCONNECT],
...
};

const connectAction = () => ({ type: SOCKET_CONNECT });

dispatch(connectAction());
```

### Disconnecting

```ts
import { CloseAction } from 'redux-ws-middleware';

const SOCKET_SEND = 'SCOKET_SEND';
const SOCKET_CONNECT = 'SOCKET_CONNECT';
const SOCKET_DISCONNECT = 'SOCKET_DISCONNECT';

const otpions = {
...
actionTypes: [SOCKET_SEND, SOCKET_CONNECT, SOCKET_DISCONNECT],
...
};

const disconnectAction = (code?: number): CloseAction => ({
type: SOCKET_DISCONNECT,
payload: { code }
});

OR

dispatch(disconnectAction(1000));
```

The `disconnectAction` can return:

```ts
{
type: SOCKET_DISCONNECT,
code
}
```

```ts
{
type: SOCKET_DISCONNECT,
payload: { code }
}
```

```ts
{
type: SOCKET_DISCONNECT,
data: { code }
}
```

(all these are supported by `CloseAction` type)

### Sending data

The data can be sent in `payload` OR in `data` key.

```ts
import { SendAction } from 'redux-ws-middleware';

const GET_POSTS = 'GET_POSTS_REQUEST';

const otpions = {
...
actionTypes: [new RegExp(/_REQUEST$/)],
...
}

const getPostsAction = (offset: number, limit: number): SendAction => ({
type: GET_POSTS,
payload: { offset, limit }
});

dispatch(getPostsAction(0, 20));
```

The `getPostsAction` can return:

```ts
{
type: GET_POSTS,
payload: { code }
}
```

```ts
{
type: GET_POSTS,
data: { code }
}
```

(all these are supported by `SendAction` type)

---

## MiddlewareOptions declaration

```ts
import { createSocketMiddleware, MiddlewareOptions } from 'redux-ws-middleware';

type ScoketReq = {
method: string
data: Record
};

type SocketRes = {
[method: string]: Record
};

type ScoketSerializedReq = {
[method: string]: Record
};

type SocketDeserializedRes = Record;

const options: MiddlewareOptions = {
url: 'ws://localhost:3000',
actionTypes: ['SEND', 'CONNECT', 'DISCONNECT'],
completedActionTypes: ['CONNECTED', 'DISCONNECTED'],

// serialize: (req: ScoketReq) => ScoketSerializedReq
serialize: ({ method, data }) => ({ [method]: data }),

// deserialize: (res: SocketRes) => SocketDeserializedRes
deserialize: (res: SocketRes) => res[Object.keys(res)[0]]
};

const socketMiddleware = createSocketMiddleware(options);
```

### Passing own types to MiddlewareOptions type

`MiddlewareOptions` is a generic type.

```ts
MiddlewareOptions
```

`Req` - type of the socket request (required).

`Res` - type of the socket response (required).

`SReq` (default is `Req`) - type of serialized socket request which will be sent to the API (not required).

**This type should be returned from the MiddlewareOptions.serialize function.**

`DRes` (default is `Res`) - type of deserialized socket response which is reachable by using hooks as `data` (not required).

**This type should be returned from the MiddlewareOptions.deserialize function.**