RSocket WebSocket Client for Browsers
rsocket-websocket-client is a JavaScript library providing a WebSocket-based RSocket client implementation primarily designed for browser environments. It is part of the broader `rsocket-js` monorepo, which aims to provide a comprehensive JavaScript implementation of the RSocket protocol. As of its current version `0.0.29-alpha.0`, it is in an active alpha development phase, indicating that it is subject to rapid changes and not yet stable for production use. RSocket is a binary protocol for application-layer communication, enabling reactive streams with models like request/response, request/stream, fire-and-forget, and channel. This client focuses specifically on the WebSocket transport, making it suitable for web applications. Its key differentiator is its adherence to the RSocket specification, offering efficient, multiplexed, and reactive communication patterns over WebSockets, in contrast to traditional REST or simpler WebSocket protocols. The release cadence is currently irregular due to its alpha status, with updates reflecting progress on the overall RSocket.js implementation.
Common errors
-
TypeError: Buffer is not defined
cause Attempting to use `Buffer.from` or other `Buffer` methods in a browser environment without a polyfill.fixIf using Webpack 5, add `resolve: { fallback: { 'buffer': require.resolve('buffer/') } }` to your `webpack.config.js`. Alternatively, explicitly use `new TextEncoder().encode(JSON.stringify(data))` for outgoing data and `new TextDecoder().decode(payload.data)` for incoming `Uint8Array`. -
Failed to connect or interact with RSocket server: Error: RSocket: Connection error.
cause Generic RSocket connection failure, often due to server not running, incorrect URL, firewall, or protocol mismatch during handshake.fixVerify the RSocket server is running and accessible at the specified URL (`ws://localhost:7000/rsocket`). Check server logs for handshake errors and ensure `dataMimeType` and `metadataMimeType` are correctly configured on both client and server. -
TypeError: client.connect is not a function
cause The `client` variable was not properly initialized as an instance of `RSocketClient` or was imported incorrectly.fixEnsure `client` is instantiated with `const client = new RSocketClient({...});` and `RSocketClient` is correctly imported as a named export from `rsocket-core`. -
TypeError: rsocket.requestResponse(...).toPromise is not a function
cause `toPromise()` is a method of `Flowable` (from `rsocket-flowable`), and `requestResponse` returns a `Flowable` which might need explicit conversion or `rsocket-flowable` might not be imported.fixEnsure `import { Flowable } from 'rsocket-flowable';` is present and wrap the `requestResponse` call: `await Flowable.from(rsocket.requestResponse(payload)).first().toPromise();`
Warnings
- breaking This package is currently in an alpha development phase (v0.0.29-alpha.0). The API is subject to frequent, significant, and breaking changes without prior notice. It is not recommended for production environments where API stability is critical.
- gotcha In browser environments, the `Buffer` global is not natively available. While `rsocket-js` often uses `Buffer` internally, payload data handling might require polyfills or explicit usage of `Uint8Array` with `TextEncoder`/`TextDecoder` for maximum compatibility.
- gotcha Mismatched `dataMimeType` or `metadataMimeType` between client and server can lead to communication failures or malformed payloads, as RSocket relies on these for proper serialization/deserialization.
- gotcha The `RSocketWebSocketClient` requires a `wsCreator` function when used in a browser environment to provide the correct `WebSocket` constructor, as Node.js's global `WebSocket` is not available.
- gotcha RSocket interactions like `requestResponse` and `requestStream` return `Flowable` instances from `rsocket-flowable`. Incorrectly handling these reactive streams (e.g., forgetting to `subscribe` or `toPromise()`) will result in no data being exchanged.
Install
-
npm install rsocket-websocket-client -
yarn add rsocket-websocket-client -
pnpm add rsocket-websocket-client
Imports
- RSocketWebSocketClient
const RSocketWebSocketClient = require('rsocket-websocket-client');import { RSocketWebSocketClient } from 'rsocket-websocket-client'; - RSocketClient
import RSocketClient from 'rsocket-core';
import { RSocketClient } from 'rsocket-core'; - BufferEncoders
const { BufferEncoders } = require('rsocket-core');import { BufferEncoders } from 'rsocket-core'; - Flowable
import { Flowable } from 'rsocket-core';import { Flowable } from 'rsocket-flowable';
Quickstart
import { RSocketClient, BufferEncoders, RSocketConnection, Payload } from 'rsocket-core';
import { RSocketWebSocketClient } from 'rsocket-websocket-client';
import { Flowable } from 'rsocket-flowable';
// For browser environments, Buffer might not be globally available.
// Use TextEncoder/TextDecoder for explicit Uint8Array handling, or rely on build tool polyfills.
// This example uses Buffer.from for simplicity, which works well in Node.js or with polyfills.
async function connectAndInteract() {
const client = new RSocketClient({
serializers: BufferEncoders,
setup: {
keepAlive: 60000, // Milliseconds
lifetime: 180000, // Milliseconds
dataMimeType: 'application/json',
metadataMimeType: 'message/x.rsocket.routing.v0', // Or 'message/x.rsocket.composite-metadata.v0'
},
transport: new RSocketWebSocketClient({
url: 'ws://localhost:7000/rsocket', // Replace with your RSocket server's WebSocket URL
// For browser environments, explicitly provide a WebSocket constructor:
wsCreator: (url) => new WebSocket(url),
}),
});
let rsocket: RSocketConnection | null = null;
try {
rsocket = await client.connect();
console.log('RSocket client connected successfully.');
// --- Request-Response interaction ---
console.log('\nSending Request-Response...');
const rrPayload: Payload = {
data: Buffer.from(JSON.stringify({ request: 'greeting' })),
metadata: Buffer.from('hello.world'), // Simple routing key
};
const rrResult = await Flowable.from<Payload>(rsocket.requestResponse(rrPayload)).first().toPromise();
console.log('Request-Response received:', rrResult.data?.toString());
// --- Request-Stream interaction ---
console.log('\nSending Request-Stream...');
const rsPayload: Payload = {
data: Buffer.from(JSON.stringify({ count: 3 })),
metadata: Buffer.from('stream.data'), // Simple routing key
};
rsocket.requestStream(rsPayload).subscribe({
onComplete: () => console.log('Request-Stream completed.'),
onError: (error) => console.error('Request-Stream error:', error),
onNext: (payload) => console.log('Request-Stream data:', payload.data?.toString()),
onSubscribe: (subscription) => subscription.request(Infinity), // Request all available items
});
// Keep the connection open for a few seconds to receive stream data
await new Promise(resolve => setTimeout(resolve, 5000));
} catch (error) {
console.error('Failed to connect or interact with RSocket server:', error);
} finally {
if (rsocket) {
client.close();
console.log('RSocket client disconnected.');
}
}
}
connectAndInteract();