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.
- Host: GitHub
- URL: https://github.com/maxzinchenko/redux-ws-middleware
- Owner: maxzinchenko
- License: mit
- Created: 2022-01-04T20:28:01.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2023-06-30T09:45:07.000Z (almost 3 years ago)
- Last Synced: 2025-05-01T04:37:05.131Z (about 1 year ago)
- Topics: middleware, redux, redux-middleware, redux-ws-middleware, websocket
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/redux-ws-middleware
- Size: 564 KB
- Stars: 4
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
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.
---
# 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.**