Exposing Services
Strata services communicate over a message bus (Redis). That's great for service-to-service communication, but browsers, mobile apps, CLI tools, and services in other languages can't talk to Redis directly.
The RPC Bridge solves this by sitting between your services and the outside world, translating HTTP and WebSocket requests into Strata service calls.
Architecture
┌──────────────┐ ┌───────┐ ┌────────────┐ ┌──────────────────┐
│ Browsers │ │ │ │ │ │ Strata Service │
│ Mobile Apps │────▶│ RPC │────▶│ Redis │────▶│ Strata Service │
│ CLI Tools │◀────│ Bridge│◀────│ (backend) │◀────│ Strata Service │
│ Other APIs │ │ │ │ │ │ │
└──────────────┘ └───────┘ └────────────┘ └──────────────────┘
HTTP / WS Strata Strata Strata
Client Protocol ServicesExternal consumers send HTTP POST requests or Socket.IO messages to the bridge. The bridge translates them into Strata requests, sends them through Redis, and returns the responses.
Quick Start
A standalone bridge in under 20 lines:
import { RPCBridgeServer } from '@strata-js/rpcbridge';
const bridge = new RPCBridgeServer({
server: {
enableHTTP: true,
enableWS: true,
port: 3000,
path: '/rpc',
excludeStack: true,
excludeUnsafeMessages: true,
},
strata: {
backend: { type: 'redis', redis: { host: 'localhost', port: 6379 } },
client: { name: 'RPCBridge' },
},
globalBlockList: [],
services: {
users: { serviceGroup: 'UserService' },
orders: { serviceGroup: 'OrderService' },
},
});
bridge.startListening();This starts an Express server on port 3000 with both HTTP and WebSocket endpoints at /rpc. Any request to the users service name gets forwarded to the UserService service group on Redis.
Integrating with an Existing Server
If you already have an Express app, you don't need a separate process for the bridge. Mount it alongside your existing routes:
import http from 'http';
import express from 'express';
import { Server as SIOServer } from 'socket.io';
import { RPCBridgeServer } from '@strata-js/rpcbridge';
const app = express();
const server = http.createServer(app);
const io = new SIOServer(server);
// Your own routes
app.get('/health', (_req, res) => { res.send('ok'); });
// Mount the bridge
new RPCBridgeServer(bridgeConfig, undefined, {
expressApp: app,
httpServer: server,
ioServer: io,
});
server.listen(3000);When providing external server instances, you manage the listener yourself — don't call startListening().
This pattern is useful when your app already has Express middleware for auth, logging, or CORS that you want the bridge to share.
Controlling Access
By default, every operation on a registered service is reachable through the bridge. You should always restrict what's exposed.
Block Lists
Deny specific operations while allowing everything else:
services: {
users: {
serviceGroup: 'UserService',
blockList: [ 'admin:*', 'internal:*' ],
},
},Allow Lists
Only permit specific operations — everything else is denied:
services: {
orders: {
serviceGroup: 'OrderService',
allowList: [ 'cart:get', 'cart:update', 'checkout:submit' ],
},
},Allow lists are the safer default. If you're exposing a service to the public internet, prefer allow lists so new operations aren't automatically reachable.
Global Block List
Applies to every service. Use this for patterns that should never be exposed:
globalBlockList: [ 'system:*', 'internal:*', 'debug:*' ],See the RPC Bridge reference for full evaluation order details.
Adding Middleware
The bridge supports middleware for both HTTP and WebSocket endpoints, injected as the second constructor argument.
HTTP Middleware
Standard Express middleware. Runs before the request is forwarded to Strata:
import type { HTTPMiddleware } from '@strata-js/rpcbridge';
const authMiddleware : HTTPMiddleware = (req, _res, next) =>
{
// Inject auth token from HTTP headers into the Strata request
req.body.auth = req.headers.authorization;
next();
};
const logger : HTTPMiddleware = (req, _res, next) =>
{
console.log(`${ req.body.serviceName }/${ req.body.context }:${ req.body.operation }`);
next();
};WebSocket Middleware
Receives the Socket.IO socket and the parsed RPC request:
import type { SocketMiddleware } from '@strata-js/rpcbridge';
const wsAuth : SocketMiddleware = (socket, rpcRequest, next) =>
{
// Pull auth from the socket's handshake
rpcRequest.auth = socket.handshake.auth?.token;
next();
};
const wsLogger : SocketMiddleware = (_socket, rpcRequest, next) =>
{
console.log(`WS: ${ rpcRequest.serviceName }/${ rpcRequest.context }:${ rpcRequest.operation }`);
next();
};Applying Middleware
new RPCBridgeServer(config, {
http: [ authMiddleware, logger ],
socket: [ wsAuth, wsLogger ],
});Calling the Bridge
HTTP
curl -X POST http://localhost:3000/rpc \
-H 'Content-Type: application/json' \
-d '{
"serviceName": "users",
"context": "profile",
"operation": "get",
"payload": { "userId": "abc123" }
}'WebSocket
import { WebSocketClient } from '@strata-js/rpcbridge-client';
const client = new WebSocketClient('http://localhost:3000/rpc');
const user = await client.request('users', 'profile', 'get', { userId: 'abc123' });For the full browser story — connection lifecycle, auth tokens, error handling — see the Building a Web UI guide.
Next Steps
- RPC Bridge reference — complete config types, interface details, and examples
- Building a Web UI — connecting a browser app to Strata services