Websockets
If you've defined a websocket server via your joystick.app()
instance on the server, you can connect to it via your component by utilizing the websockets
property on your component options.
/ui/pages/index/index.js
import joystick from '@joystick.js/ui';
const Index = joystick.component({
websockets: (instance = {}) => {
return {
example_endpoint: {
options: {
logging: true,
auto_reconnect: true,
},
events: {
on_open: (connection = {}) => {
console.log('Connection to example_endpoint opened!');
},
on_message: (message = {}) => {
console.log('Message received from server:', message);
},
on_close: (code = 0, reason = '', connection = {}) => {
console.log('Connection to example_endpoint closed.', { code, reason });
},
},
},
};
},
events: {
'submit form': (event = {}, instance = {}) => {
instance.websockets.example_endpoint.send({
message: event.target.message.value,
});
},
},
render: ({ state, when }) => {
return `
<form>
<input type="text" name="message" placeholder="Type your message here.." />
<button type="submit">Send Message</button>
</form>
`;
},
});
export default Index;
Above, we've defined a connection to our hypothetical websocket server at ws://localhost:2600/api/_websockets/example_endpoint
. To do it, we pass the option websockets
to our component options as a function
that returns an object
defining the websocket endpoints we want to connect to. On that object
, we define key/value pairs where the key is the name of a websocket endpoint we want to connect to (example_endpoint
) and the value is an object defining the behavior of the websocket client.
Here, we set options.logging
to true
to enable logging on all websocket connection activity and options.auto_reconnect
to true
to establish an auto-reconnect interval in the event that our connection to the server closes.
Next, we define events
to listen for as an object
containing methods for the three different events we can listen for: on_open()
, on_message()
, and on_close()
.
Behind the scenes, with this, Joystick will automatically establish a websocket client connection for us and assign the connection back to our component instance at instance.websockets.example_endpoint
.
Utilizing that value, we've added an event listener on the submit
event of the <form></form>
element our component is rendering. When it does, we want to send a websocket message back to our server with the value of our input. To do it, we call the .send()
method of our instance.websockets.example_endpoint
value, passing an object that will be automatically stringified and sent to our server.
Filtering messages with query params
By default, WebSocket connections to a given server receive all messages sent from that server. In some cases, a WebSocket client may want to receive messages selectively, for example, in a chat app where it only wants to receive messages for the currently focused user and not all users.
To filter message traffic, an additional query
object can be specified with a nested id
field specifying a unique ID to filter messages by:
/ui/pages/index/index.js
import joystick, { accounts } from '@joystick.js/ui';
const Index = joystick.component({
data: async () => {
return {
user: await accounts.user(),
};
},
websockets: (instance = {}) => {
return {
example_endpoint: {
options: {
logging: true,
auto_reconnect: true,
},
query: {
id: instance?.data?.user?._id,
},
events: {
on_open: (connection = {}) => {
console.log('Connection to example_endpoint opened!');
},
on_message: (message = {}) => {
console.log('Message received from server:', message);
},
on_close: (code = 0, reason = '', connection = {}) => {
console.log('Connection to example_endpoint closed.', { code, reason });
},
},
},
};
},
events: { ... },
render: ({ state, when }) => { ... },
});
export default Index;
As an example, above, we've extended our component to include a data function which allows us to fetch the current user via the accounts.user()
method and pass it to our app via instance.data
. With this, when we establish our WebSocket client connection, we add an additional query
object to our example_endpoint
options, setting the nested id
field to instance?.data?.user?._id
, or, the currently logged in user's ID.
On the server, now, we can anticipate this ID being passed and filter messages that we send to clients via this ID.
API Reference
Websockets API
websockets: (instance: object) => {
return {
websocket_name: {
options: {
logging: boolean;
auto_reconnect: boolean; // Alias autoReconnect
},
query: {
id: string;
},
events: {
on_open(connection: object) => void;
on_message(message: object) => void;
on_close(code: integer, reason: string, connection: object) => void;
}
}
}
};