Mengimplementasikan WebSocket di Hono: setup endpoint dengan upgradeWebSocket, onOpen, onMessage, onClose handlers, typed messages, broadcast, dan room management untuk aplikasi real-time.

Setelah di episode 13 kita mengimplementasikan guard pattern, pada episode ini kita akan memahami WebSocket — protokol komunikasi real-time yang memungkinkan server mengirim data ke client tanpa diminta. WebSocket adalah fondasi untuk chat apps, live notifications, dan game state sync.
import { Hono } from 'hono'
import { upgradeWebSocket } from 'hono/cloudflare-workers'
const app = new Hono()
app.get('/ws', upgradeWebSocket((c) => ({
onOpen(event, ws) {
console.log('Client connected')
ws.send(JSON.stringify({ type: 'welcome', message: 'Connected!' }))
},
onMessage(event, ws) {
console.log('Received:', event.data)
ws.send(JSON.stringify({ type: 'echo', data: event.data }))
},
onClose(event, ws) {
console.log('Client disconnected')
},
})))const ws = new WebSocket('ws://localhost:8787/ws')
ws.onopen = () => {
ws.send(JSON.stringify({ type: 'chat', message: 'Hello!' }))
}
ws.onmessage = (event) => {
console.log('Server:', JSON.parse(event.data))
}import { z } from 'zod'
const messageSchema = z.object({
type: z.enum(['chat', 'join', 'leave']),
message: z.string(),
room: z.string().optional(),
})
app.get('/ws', upgradeWebSocket((c) => ({
onMessage(event, ws) {
const result = messageSchema.safeParse(JSON.parse(event.data as string))
if (!result.success) {
ws.send(JSON.stringify({ error: 'Invalid message' }))
return
}
const { type, message, room } = result.data
if (type === 'chat') {
ws.send(JSON.stringify({ type: 'chat', message }))
}
},
})))const clients = new Set<any>()
app.get('/ws', upgradeWebSocket((c) => ({
onOpen(event, ws) {
clients.add(ws)
},
onMessage(event, ws) {
for (const client of clients) {
client.send(event.data)
}
},
onClose(event, ws) {
clients.delete(ws)
},
})))const rooms = new Map<string, Set<any>>()
function joinRoom(ws: any, room: string) {
if (!rooms.has(room)) rooms.set(room, new Set())
rooms.get(room)!.add(ws)
}
function broadcastToRoom(room: string, message: string) {
const clients = rooms.get(room)
if (!clients) return
for (const client of clients) {
client.send(message)
}
}
app.get('/ws', upgradeWebSocket((c) => ({
onOpen(event, ws) {
joinRoom(ws, 'general')
},
onMessage(event, ws) {
broadcastToRoom('general', event.data as string)
},
onClose(event, ws) {
for (const [room, clients] of rooms) {
clients.delete(ws)
if (clients.size === 0) rooms.delete(room)
}
},
})))Note
WebSocket menggunakan koneksi persistent. Untuk production di Cloudflare Workers, pertimbangkan menggunakan Durable Objects untuk state management yang persistent across requests.
Pada episode 14 ini, kalian telah memahami WebSocket di Hono — dari setup endpoint hingga typed messages dan room management.
Inti yang harus dibawa pulang:
upgradeWebSocket() mengkonversi HTTP ke WebSocket connection.onOpen, onMessage, onClose adalah lifecycle handlers.Di episode 15 selanjutnya kita akan memahami OpenAPI dan API documentation — auto-generate Swagger UI, hono-openapi, dan export spec. Sampai jumpa di episode 15!