Skip to main content
Version: Next

Communication Protocols

The system supports multiple communication methods between client and server.

Protocol Comparison

ProtocolEndpointType SafetyReal-timeUse Case
REST/api/*❌ Manual❌ NoExternal APIs, simple requests
tRPC HTTP/trpc/*✅ Full❌ NoType-safe queries/mutations
tRPC WebSocket/trpc✅ Full✅ YesReal-time sync, subscriptions

REST API (Hono)

Traditional HTTP endpoints with JSON.

Example: REST Request

// Client-side fetch
const response = await fetch('http://localhost:8787/api/customers');
const customers = await response.json();

// POST with body
await fetch('http://localhost:8787/api/customers', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
ContactName: 'John Doe',
CompanyName: 'ACME Inc',
}),
});

Pros/Cons

ProsCons
Universal, works anywhereNo type safety
Simple to debug (curl, Postman)Manual request/response typing
Cache-friendlyNo real-time

tRPC HTTP

Type-safe RPC over HTTP.

Example: tRPC HTTP Request

// Using @trpc/client
import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from 'cloudflare-d1-worker';

const client = createTRPCClient<AppRouter>({
links: [
httpBatchLink({
url: 'http://localhost:8787/trpc',
}),
],
});

// Full type inference!
const customers = await client.getCustomers.query({});
const result = await client.createCustomer.mutate({
CustomerId: '123',
ContactName: 'John',
CompanyName: 'ACME',
});

Pros/Cons

ProsCons
Full type safetyExtra dependency
Auto-complete in IDELearning curve
Validation with ZodNot universal (JS only)

tRPC WebSocket

Real-time tRPC over WebSocket.

Why WebSocket?

  • Lower latency: No HTTP overhead per request
  • Bidirectional: Server can push to client
  • Connection reuse: Single connection for all calls

Example: WebSocket tRPC Client

import { createTRPCClient, wsLink } from '@trpc/client';
import type { AppRouter } from 'cloudflare-d1-worker';

const client = createTRPCClient<AppRouter>({
links: [
wsLink({
url: 'ws://localhost:8787/trpc',
}),
],
});

// Same API, but over WebSocket
const result = await client.healthCheck.query();

Server-Side WebSocket Handler

// ws-adapter.ts - Custom JSON-RPC over WebSocket
import { AnyRouter, TRPCError } from '@trpc/server';

interface JSONRPCRequest {
id: number | string;
method: 'query' | 'mutation';
params: {
path: string;
input?: unknown;
};
}

export async function processTRPCMessage(
data: unknown,
router: AnyRouter,
ctx: any
): Promise<string | null> {
const msg = JSON.parse(data as string) as JSONRPCRequest;

// Create a caller and execute the procedure
const caller = router.createCaller(ctx);
const parts = msg.params.path.split('.');

let fn: any = caller;
for (const part of parts) {
fn = fn?.[part];
}

const result = await fn(msg.params.input);

return JSON.stringify({
id: msg.id,
result: { type: 'data', data: result },
});
}

Hono WebSocket Integration

import { upgradeWebSocket } from 'hono/cloudflare-workers';
import { processTRPCMessage } from './ws-adapter';

app.get('/trpc', upgradeWebSocket((c) => ({
async onMessage(event, ws) {
const response = await processTRPCMessage(
event.data,
appRouter,
{ env: c.env }
);
if (response) ws.send(response);
},
onClose: () => console.log('Connection closed'),
})));

Choosing a Protocol

Recommendations

ScenarioRecommendation
External webhookREST
Simple CRUD from other servicesREST
Internal app with TypeScripttRPC HTTP
Real-time synctRPC WebSocket
SubscriptionstRPC WebSocket