Skip to Content
Jumentix DocsGuidesCreate a Realtime API

Creating Realtime API with Jumentix

Responsibility in context

  • Owns: Realtime adapters (Socket.IO / gRPC) around the same use-cases
  • Used with: sdk-websocket-client, sdk-grpc-client, shared-contracts
  • Not responsible for: Plain REST-only flows or browser IndexedDB

What it is

This guide covers enabling push and bidirectional communication on top of the backend template using WebSocket (browser-friendly) or gRPC (server-to-server), with REST kept as an operational fallback.

Why it exists

Many products need live updates — chat, notifications, dashboards — but teams bolt WebSocket code onto REST controllers and lose contract alignment. Jumentix treats AsyncAPI like OpenAPI: channels and payloads are specified first, handlers invoke the same controllers and use cases as REST, and degraded realtime falls back to HTTP.

Prerequisites

ItemRequiredNotes
Bun 1.3.13+YesGetting started
Working REST profileRecommendedComplete REST guide first
AsyncAPI specsYesUnder spec/ alongside OpenAPI
Env fileYesapps/backend-template/src/config/.env.dev

Glossary

TermMeaning on this page
Realtime APINon-HTTP primary interface — WebSocket or gRPC — for push/pull messaging.
AsyncAPISpec describing channels, messages, and payload schemas for realtime.
WebSocketBrowser-friendly persistent connection; default protocol for SPAs.
gRPCBinary RPC protocol; use for service-to-service, not browser clients.
REST fallbackHTTP endpoints still available when realtime channel is down or unsupported.
Message handlerAdapter code receiving a message, calling a controller, replying on same correlation id.
Correlation idToken linking a client request to its response on the same socket.
JUMENTIX_REALTIME_APIEnv flag yes/no enabling realtime startup profile.

Numbered steps

Step 1 — Enable the realtime runtime profile (< 5 minutes)

  1. Edit your env file:
JUMENTIX_REALTIME_API=yes JUMENTIX_REALTIME_API_PROTOCOL=websocket # or grpc JUMENTIX_HTTP_FRAMEWORK=express # REST fallback + docs
  1. Start the matching dev profile from monorepo root:
# WebSocket + REST fallback (start here for browser apps) bun run dev:websocket # gRPC + REST fallback (Node service mesh) bun run dev:grpc

From apps/backend-template you can also run bun run dev:websocket-rest or bun run dev:grpc-rest.

Success check: PM2 shows the websocket or grpc process online; REST /health still responds.

Step 2 — Define Async contracts (< 15 minutes)

  1. Add or update AsyncAPI files under spec/ — define channels, messages, and payload schemas.
  2. Align payload shapes with domain models and controller method signatures.
  3. Reference shared error/response contracts in handler implementations — same types as REST DTOs where possible.
  4. Cross-check Events and messages for naming conventions.

Success check: AsyncAPI channel names match handler registrations; no orphan messages.

Step 3 — Implement message handlers (< 30 minutes)

WebSocket path (browser apps):

  1. Handler receives framed message on a channel.
  2. Handler parses payload → calls controller method.
  3. Handler sends response on the same client connection using the message correlation id.

gRPC path (Node-to-Node):

  1. gRPC service method receives protobuf request.
  2. Invokes the same controller used by REST.
  3. Returns protobuf response mapped from domain result.

Rule: controllers and use cases stay identical — only adapter code differs from REST.

Success check: unit/integration test invokes handler without starting full cluster.

Step 4 — Keep REST fallback available (< 5 minutes)

Realtime services always run with REST as a secondary interface:

  • Operational tools and degraded mode use REST endpoints.
  • OpenAPI docs remain the backup contract when sockets fail.
  • Do not delete REST routes when adding realtime — clients may downgrade gracefully.

Success check: with realtime process stopped, REST endpoints still serve critical reads.

Step 5 — Validate realtime stability (< 10 minutes)

From monorepo root:

bun run test:integration:realtime bun run test:smoke:realtime

For Redis-backed Socket.IO scaling (optional advanced path):

bun run test:integration:realtime:redis-streams

Success check: both commands exit 0; smoke test covers connect → message → response.

Step 6 — Client integration (junior path)

Prefer WebSocket for browser apps. gRPC stays Node-to-Node — use static snippets on the gRPC adapter page, not a browser Run button.

Static subscribe pattern:

const ws = api.createMockClient();
const sub = await ws.subscribe({ channel: 'notifications' });
sub.on('message', (msg) => console.log(msg.payload));

Examples

Interactive WebSocket client playground

WebSocket client with fake socket

Use the realtime client contract to create and list Task records in the browser.

const client = api.createFakeClient();
const status = await client.connect();

const created = await client.request({
  operationId: 'tasks.create',
  input: {
    id: 'task-1',
    title: 'Render realtime updates',
    categoryId: 'home',
    completed: false
  }
});
const listed = await client.request({
  operationId: 'tasks.list',
  input: { categoryId: 'home' }
});
const closed = await client.disconnect();

return {
  status,
  created,
  listed,
  closed
};

Success check: Run connects mock client, receives a message; Reset clears state.

Common errors

SymptomLikely causeFixVerify success
Realtime starts but REST 404HTTP adapter not loaded in combined profileKeep JUMENTIX_HTTP_FRAMEWORK=express; use dev:websocket not raw socket only/health returns 200
Handler never repliesMissing correlation id on responseEcho client message id in adapter replyIntegration test green
Browser cannot use gRPCgRPC is not a browser protocolUse WebSocket for SPA; gRPC for backend servicesWS playground Run green
test:integration:realtime fails on grpcWrong JUMENTIX_REALTIME_API_PROTOCOLMatch env to script (websocket vs grpc)Target protocol test passes
Duplicate message handlingHandler registered twiceOne registration per channel in adapter bootstrapSingle response per send
Redis streams test skippedRUN_REDIS_INTEGRATION not setStart redis compose; set env flagredis-streams integration green

Junior checklist (“I can …”)

  • Set JUMENTIX_REALTIME_API=yes and choose websocket or grpc.
  • Start bun run dev:websocket and confirm REST fallback still works.
  • Locate AsyncAPI under spec/ and name one channel and its payload schema.
  • Trace one message: adapter handler → controller → use case.
  • Run bun run test:integration:realtime and bun run test:smoke:realtime.
  • Use the sdk-websocket-client playground (Run green).
  • Explain when to choose gRPC instead of WebSocket.

Next step

Build the frontend that consumes these channels in Create a SPA or Offline PWA. For adapter details, see WebSocket adapter and gRPC adapter.