Skip to main content

Real Time

RestAPI.com provides real-time capabilities for detecting database changes and enabling direct client-to-client communication.

Prerequisites

To use real-time subscriptions on a collection, you must configure LISTEN access:

{ "method": "LISTEN", "roleNames": ["_AUTHENTICATED_USER"] }

Without LISTEN access, clients cannot subscribe to changes on that collection. Configure this in the Developer Portal under your collection's Access settings, or in your schema JSON.

Features

  • Database change detection — Subscribe to collection changes as they happen
  • Client-to-client messaging — Direct peer-to-peer communication via channels
  • Server-to-client messaging — Push updates from functions to connected clients

Connection Options

Choose your preferred protocol:

ProtocolLibrary
Azure Web PubSub@azure/web-pubsub-client
SignalR@microsoft/signalr

Setting Up Connections

Azure Web PubSub

import { WebPubSubClient } from '@azure/web-pubsub-client';

const client = new WebPubSubClient({
getClientAccessUrl: async () => {
const response = await fetch('/api/_rt/ws');
return response.text();
}
});

await client.start();

SignalR

import * as signalR from '@microsoft/signalr';

const connection = new signalR.HubConnectionBuilder()
.withUrl('/api/_rt/signalr')
.withAutomaticReconnect()
.build();

await connection.start();

Listening for Changes

SignalR

connection.on('change', (data) => {
console.log('Data changed:', data);
});

Web PubSub

client.on('group-message', (event) => {
console.log('Message received:', event.message);
});

Entity Subscriptions

Subscribe to database changes on a collection using the /_listen endpoint:

await fetch('/api/products/_listen', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
connectionId: myConnectionId,
type: 'ws' // or 'signalr'
})
});

Entity subscriptions are read-only — clients receive notifications but cannot send messages to entity channels. This ensures data integrity since entity notifications are controlled by the server.

Filtering Subscriptions

Subscribe to a specific item:

body: JSON.stringify({
connectionId: myConnectionId,
type: 'ws',
id: 'item-uuid' // Only receive changes for this item
})

Filter by lookup relationships:

body: JSON.stringify({
connectionId: myConnectionId,
type: 'ws',
lookupIds: ['parent-uuid-1', 'parent-uuid-2'] // Filter by parent references
})

Channel-Based Communication

Channels enable direct client-to-client messaging. There are two types:

Regular Channels

Standard channels where clients can join and send messages freely:

// Join a channel
await fetch('/api/_rt/join', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
connectionId: myConnectionId,
channel: 'my-room'
})
});

Clients can send messages via the API or directly via WebPubSub SDK:

// Via API
await fetch('/api/_rt/send', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
channel: 'my-room',
body: { type: 'chat', text: 'Hello!' }
})
});

// Direct client-to-client (Web PubSub) - channel prefixed with API name
client.sendToGroup('my-api:my-room', { text: 'Hello!' });

Gated Channels (Server-Controlled)

Channels with : in the name can only be joined and messaged via server-side functions. The function controls access and whether clients can send.

Use cases:

  • Chat rooms - Function validates access, then clients can chat
  • Broadcasts - Function adds listeners, only server sends messages
  • Game lobbies - Function manages who can join and participate
// In a trigger function - add client with send permission
await post('_rt/join', {
connectionId: request.connectionId,
channel: 'game:room-123',
readOnly: false // Client can send messages
});

// Or add client as read-only listener
await post('_rt/join', {
connectionId: request.connectionId,
channel: 'announcements:system',
readOnly: true // Client can only receive
});

// Server can always send to any channel
await post('_rt/send', {
channel: 'announcements:system',
body: { text: 'Server maintenance in 10 minutes' }
});

Clients cannot directly join or send to gated channels:

// This will fail with 400 Bad Request
await fetch('/api/_rt/join', {
body: JSON.stringify({
connectionId: myConnectionId,
channel: 'game:room-123' // Rejected - contains ':'
})
});

Channel Type Summary

Channel TypeClient JoinClient SendServer JoinServer Send
Regular (my-room)YesYesYesYes
Gated (game:room)NoconfigurableYesYes
Entity (/products/_listen)N/ANoN/AYes (automatic)

Channel Naming Rules

  • Channel names with : are server-controlled (gated channels)
  • Channel names cannot match collection names (use /_listen for entity subscriptions)
  • Channel names are scoped to your API (internally prefixed with api-name:)

Endpoints

EndpointMethodDescription
/api/_rt/wsGETGet WebSocket URL for Web PubSub
/api/_rt/signalrGETGet SignalR connection info
/api/_rt/joinPOSTJoin a channel
/api/_rt/sendPOSTSend message to a channel
/api/{collection}/_listenPOSTSubscribe to entity changes

Use Cases

  • Live dashboards — Update metrics in real time
  • Chat applications — Direct messaging between users
  • Collaborative editing — Sync changes across clients
  • Notifications — Push updates to connected users
  • Gaming — Real-time game state synchronization