Introduction
Building a real-time notifications system is integral to many modern web applications. It enhances user experience by instantly delivering updates. One of the most effective ways to implement such a system is using WebSockets. In this article, we will explore how to create a real-time notifications system in Go using WebSockets.
What are WebSockets?
WebSockets are a protocol that enables bidirectional, full-duplex communication channels over a single TCP connection. Unlike HTTP, which is unidirectional, WebSockets allow data to be transmitted interactively between a client and a server with low latency.
Setting Up a WebSocket Server in Go
First, let's set up a WebSocket server using Go. We'll use the github.com/gorilla/websocket package, a popular library that simplifies handling WebSocket connections in a performant and secure way.
package main
import (
"fmt"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true // For demo purposes, accept all origins.
},
}
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
for {
_, msg, err := ws.ReadMessage()
if err != nil {
fmt.Println("Error reading message:", err)
break
}
fmt.Printf("Received: %s\n", msg)
err = ws.WriteMessage(websocket.TextMessage, msg)
if err != nil {
fmt.Println("Error writing message:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", handleConnections)
fmt.Println("WebSocket server started at ws://localhost:8080/ws")
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("Server error:", err)
}
}
Testing the WebSocket Server
To test our server, we can use browser developer tools or a WebSocket client like Postman. Open your browser console and run the following JavaScript:
let socket = new WebSocket("ws://localhost:8080/ws");
socket.onopen = function(e) {
console.log("Connected to server");
socket.send("Hello Server!");
};
socket.onmessage = function(event) {
console.log(`Data received from server: ${event.data}`);
};
socket.onclose = function(event) {
if (event.wasClean) {
console.log(`Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
console.error('Connection died');
}
};
socket.onerror = function(error) {
console.error(`[error] ${error.message}`);
};
Handling Notifications
To send notifications, create a function on the server that broadcasts messages to all connected clients:
var clients = make(map[*websocket.Conn]bool) // client set
func handleConnections(w http.ResponseWriter, r *http.Request) {
ws, err := upgrader.Upgrade(w, r, nil)
if err != nil {
fmt.Println(err)
return
}
defer ws.Close()
clients[ws] = true
for {
_, msg, err := ws.ReadMessage()
if err != nil {
fmt.Println("Error reading message:", err)
delete(clients, ws)
break
}
broadcast(msg)
}
}
func broadcast(message []byte) {
for client := range clients {
err := client.WriteMessage(websocket.TextMessage, message)
if err != nil {
fmt.Println("Error writing to a client:", err)
client.Close()
delete(clients, client)
}
}
}
Conclusion
You have implemented a basic real-time notifications system using WebSockets in Go. This implementation serves as a foundation to build more complex features into your real-time application, such as user-specific messages, rooms, or channels. With WebSockets, you'll enhance user interaction through instantaneous communication, making applications feel more responsive and engaging.