Handlers, not a switch
Each action gets a typed method: HandleChat(ctx, ChatMessage). No json.RawMessage, no switch on msg.Type.
Write a struct of handlers. chanx-go routes each frame to the right one, validates it first, broadcasts across processes and documents it all as AsyncAPI, on the same protocol as Python chanx.
type ChatConsumer struct{}
// Groups puts each connection in its room, from the {room} path parameter.
func (ChatConsumer) Groups(c *chanx.Conn) []string { return []string{"room." + c.Param("room")} }
// Emits declares what the consumer sends besides replies.
func (ChatConsumer) Emits() []chanx.Message { return []chanx.Message{ChatNotification{}} }
func (ChatConsumer) HandleChat(ctx *chanx.Context, m ChatMessage) error {
return ctx.Broadcast(ChatNotification{Payload: m.Payload})
}
func (ChatConsumer) HandlePing(ctx *chanx.Context, _ chanx.PingMessage) (chanx.PongMessage, error) {
return chanx.PongMessage{}, nil
}Mount it, and two clients in /ws/chat/lobby talk:
> {"action": "chat", "payload": {"text": "hi"}}
< {"action": "chat_notification", "payload": {"text": "hi"}}A frame that does not match the message never reaches HandleChat:
> {"action": "chat", "payload": {"txt": "hi"}}
< {"action": "error", "payload": [{"type": "missing", "loc": ["chat", "payload", "text"], "msg": "Field required"}]}The server documents itself at /asyncapi.json. Generate a typed client from it, in Go with chanx-codegen or in TypeScript with @chanx-js/codegen, and a misspelled field fails to compile instead of reaching the server.
Build it in five minutes, or read what chanx-go is first.