Skip to content

Why chanx-go? ​

Go has excellent WebSocket libraries, gorilla/websocket and coder/websocket, but they stop at the socket. Everything after the upgrade is left to you, and every team writes the same loop:

go
for {
	var msg struct {
		Action  string          `json:"action"`
		Payload json.RawMessage `json:"payload"`
	}
	if err := conn.ReadJSON(&msg); err != nil {
		return
	}
	switch msg.Action {
	case "chat":
		var p ChatPayload
		if json.Unmarshal(msg.Payload, &p) != nil || p.Text == "" {
			conn.WriteJSON(map[string]string{"error": "bad payload"})
			continue
		}
		hub.Broadcast(room, p) // your own hub, and one process only
	case "ping":
		// ...
	}
}

Then it grows: a hub for rooms, Redis pub/sub once there is more than one process, a validation helper per message, and API docs written by hand that fall behind the code.

With chanx-go, the same chat is a struct and a method:

go
type ChatMessage struct {
	chanx.BaseMessage `action:"chat"`
	Payload           ChatPayload `json:"payload"`
}

func (ChatConsumer) HandleChat(ctx *chanx.Context, m ChatMessage) error {
	return ctx.Broadcast(ChatNotification{Payload: m.Payload})
}

The loop, the validation, the hub and the docs are chanx-go's job, written once and tested.

What you get ​

You writechanx-go does
A struct per messageinfers its JSON Schema, validates every frame, answers bad ones with an error frame
A method per handlerroutes each frame by action, echoes the ref on replies, recovers panics
Groups and ctx.Broadcastjoins and leaves groups, fans out across processes over the layer
A topic structsubscribe, unsubscribe, authorization, per-topic handlers, over one socket
Authenticateruns it once, reports the result, closes with 4401 or 4403 on failure
Nothing morean AsyncAPI 3 document, a docs page, and typed clients generated from it

Compared with what Go has ​

ProjectWhat it isHow it differs
gorilla/websocket, coder/websocketWebSocket connectionsThe layer below. chanx-go runs on either
melodysessions and broadcastNo typed messages, no cross-process groups, no documentation
Centrifugea mature real-time pub/sub serverIts own protocol and SDKs; a broker, not typed request and reply handlers. The right pick for a pure pub/sub server
Socket.IO portsevents and roomsUntyped payloads, no schema, the Socket.IO protocol
asyncapi3, swaggest/go-asyncapiAsyncAPI documents from Go typesDocuments only, declared beside the server. chanx-go's comes from the handlers that run

One protocol, three languages ​

chanx-go is a third implementation of the chanx protocol, after Python and TypeScript. That brings more than familiarity:

  • Clients work unchanged. @chanx-js/client and the clients generated by @chanx-js/codegen or Python's chanx generate-client talk to a Go server as they do to a Python one.
  • One Redis, every language. The Redis layer is wire-compatible with channels_redis, fast-channels and @chanx-js/layers. A Go worker can push to sockets held by a Django server, and the other way round.
  • Parity is tested, not claimed. Validation errors, group names, key casing, the Redis encodings and the whole AsyncAPI document are checked against values recorded from Python chanx. The few deliberate differences are listed in Differences from Python.

Who it is for ​

  • Go teams building chat, notifications, live dashboards, collaboration or AI streaming, who want structure rather than a raw socket.
  • Teams already on chanx in Python who move a service to Go, or run both side by side.
  • Frontend teams who want a typed client generated from the server, not written by hand.

Next: the quick start.

MIT licensed