Skip to main content

Real-time API

The Codehooks.io real-time API enables applications and clients to publish and subscribe to data events.

API quick overview

State diagram

The following diagram shows the necessary dataflow between a client and a server.

realtime.createChannel(channel)

Create a real-time channel for clients listeners and and server publishers.

Parameters

  • channel: string - e.g. '/goals'

Returns: void.

Code example for creating a channel

index.js
import { app, realtime } from 'codehooks-js';

// create a real-time channel
realtime.createChannel('/goals');

/* more code here ... */

// bind to serverless runtime
export default app.init();

realtime.publishEvent(channel,data, [query])

Publish a data event on a channel to all or some (query) listeners.

Parameters

  • channel: string - e.g. '/goals'
  • data: object - Event object to publish
  • query: object - optional matching criteria for listeners to get the event

Returns: Promise: object

Code example for publish events

index.js
import { app, realtime } from 'codehooks-js';

// create a real-time channel
realtime.createChannel('/goals');

// broadcast event
async function someFunction() {
const listeners = { topic: 'score' }; // send to all listeners subscribing to topic
const event = { 'team A': 0, 'team B': 1, player: 'Messi' };
const data = await realtime.publishEvent('/goals', event, listeners);
}

/* more logic here ...*/

// bind to serverless runtime
export default app.init();

realtime.createListener(channel, data)

Create a new listener (ID) that clients can use to subscribe to an EventSource channel.

Parameters

  • channel: string - Channel name, e.g. '/goals'
  • data: object - Listener topics of interest, e.g. {topic: "score"}

Returns: Promise: listenerData with a unique _id

Code example for creating a new listener

index.js
import { app, realtime } from 'codehooks-js';

// create a real-time channel
realtime.createChannel('/clock');

// client rest api to connect to the real time channel
app.post('/connect', async (req, res) => {
const listenerData = await realtime.createListener('/clock', req.body);
// return listener ID to client
res.json({ listenerID: listenerData._id });
});

app.job('* * * * *', async (req, res) => {
const listeners = { topic: 'tick' }; // send to all listeners subscribing to topic
const event = { 'The time is': new Date() };
const data = await realtime.publishEvent('/clock', event, listeners);
});

// bind to serverless runtime
export default app.init();

realtime.getListener(channel, listenerID)

Get a listener object for a specific listener (ID) on a channel.

Parameters

  • channel: string - Channel name, e.g. '/goals'
  • listenerID: string - A valid _id for an existing listener

Returns: Promise: listenerData

realtime.getListeners(channel)

Get all listeners on a channel (channel).

Parameters

  • channel: string - Channel name, e.g. '/goals'

Returns: Promise: array of listenerData

realtime.removeListener(channel, listenerID)

Remove a listener (listenerID) from a channel (channel).

Parameters

  • channel: string - Channel name, e.g. '/goals'
  • listenerID: string - A valid _id for an existing listener

Returns: Promise: listenerData

Complete code example - Real-time chat

To better understand how the Codehooks.io real-time API works, check out the following code example. The complete source code, including install instructions, is avaliable at Github.

The code example is a simple web (plain vanilla ugly HTML) chat app for POST'ing messages to a REST API endpoint. The messages are then received on the client in real-time from the server. The server (Codehooks.io) uses the real-time API to subscribe and publish data to/from client requests.

real-time web chat

You can test out a live example here

HTML client page

/public/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Codehooks.io - Chat App</title>
<link rel="stylesheet" href="styles.css" />
<script src="https://unpkg.com/[email protected]/src/eventsource.js"></script>
</head>

<body>
<h1>Codehooks.io - Chat example</h1>

<div id="chat">
<label for="aliasInput">Chat Alias:</label>
<input type="text" id="aliasInput" placeholder="Enter your alias..." />
<div id="status">
Real-time status:
<span id="statusIndicator" style="color: red;">Initializing</span>
</div>
<div
id="messages"
style="height: 150px; overflow: auto; border: 1px solid #ccc; margin-bottom: 10px;"
></div>
<div id="inputContainer" style="display: flex; width: 100%;">
<input
type="text"
id="messageInput"
placeholder="Type a message..."
style="flex-grow: 1; margin-right: 10px;"
/>
<button id="sendButton">Send</button>
</div>
</div>
<script src="chat.js"></script>
</body>
</html>

HTML client JavaScript

/public/chat.js
const API_TOKEN = '0a2249d4-5f10-489c-8229-1f060ad1e0f6';
let listenerID = null;

document.addEventListener('DOMContentLoaded', function () {
const aliasInput = document.getElementById('aliasInput');
const messageInput = document.getElementById('messageInput');
const sendButton = document.getElementById('sendButton');

// Function to send a message to the server
function sendMessage(message) {
fetch('/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-apikey': API_TOKEN,
},
body: JSON.stringify({
message: message,
listenerID,
alias: aliasInput.value.trim(),
}),
})
.then((response) => response.json())
.then((data) => {
console.log('Message sent:', data);
messageInput.value = ''; // Clear input after sending
messageInput.focus(); // Keep focus on input field
})
.catch((error) => {
console.error('Error:', error);
});
}

sendButton.addEventListener('click', function () {
if (messageInput.value) {
sendMessage(messageInput.value);
}
});

messageInput.addEventListener('keydown', function (event) {
// Check if Enter key is pressed without Shift key
if (event.key === 'Enter' && !event.shiftKey) {
event.preventDefault(); // Prevent default to avoid line breaks or form submission
if (messageInput.value) {
sendMessage(messageInput.value);
}
}
});
// init real-time connection
startListener();
});

function addMessage(message) {
const messagesDiv = document.getElementById('messages');
const messageElement = document.createElement('div');
messageElement.textContent = message;
messagesDiv.appendChild(messageElement); // Adds the message at the bottom
// Auto-scroll to the bottom
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}

// connect to realtime SSE
async function startListener() {
// setup the real time stuff
const statusIndicator = document.getElementById('statusIndicator');

const interests = {}; // everything
var requestOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-apikey': API_TOKEN,
},
body: JSON.stringify(interests),
};
// get a real time listenerID
console.log('Connect request', requestOptions);
const response = await fetch('/connect', requestOptions);
const result = await response.json();
listenerID = result.listenerID;
console.log('GOT clientID', result);

// connect to reatime channel
let eventSource = new EventSourcePolyfill(`/chat/${result.listenerID}`, {
headers: {
'x-apikey': API_TOKEN,
},
});
statusIndicator.textContent = 'Connected';
statusIndicator.style.color = 'green';

// incoming message event
eventSource.onmessage = function (event) {
console.log('Event', event.data);
const result = JSON.parse(event.data);
addMessage(result.message);
};

// here we go
eventSource.onopen = function (event) {
// Connection is open
statusIndicator.textContent = 'Live data ready';
statusIndicator.style.color = 'green';
};
// oops, reconnecting if possible
eventSource.onerror = function (event) {
console.log('Error', event);
// An error occurred or the connection was closed
if (eventSource.readyState == EventSource.CLOSED) {
console.log('Connection was closed.');
}
statusIndicator.textContent = 'No connection';
statusIndicator.style.color = 'red';
};

return result;
}

Codehooks.io Server

See install and deploy docs at Github.

index.js
// Codehooks.io - Chat example

import { app, realtime } from 'codehooks-js';

// create a real-time channel
realtime.createChannel('/chat');

// client connects for a new real-time listener ID
app.post('/connect', async (req, res) => {
const listenerData = await realtime.createListener('/chat');
// return listener ID to client
res.json({ listenerID: listenerData._id });
});

// client post a new message
app.post('/messages', async (req, res) => {
console.log('Message in', req.body);
const { message, listenerID, alias } = req.body;
const data = await realtime.publishEvent('/chat', {
message: `${alias || 'Anonymous'}: ${message}`,
});
res.end(data);
});

// annoying message from a cron job every second minute ;)
app.job('*/2 * * * *', async (_, job) => {
const message = `Hello from cron job at ${new Date().toISOString()}`;
const data = await realtime.publishEvent('/chat', {
message: `cron: ${message}`,
});
job.end();
});

app.static({ route: '/public', directory: '/public' });

// bind to serverless runtime
export default app.init();