Sling Academy
Home/Golang/Building a Real-Time Notifications System Using WebSockets in Go

Building a Real-Time Notifications System Using WebSockets in Go

Last updated: November 26, 2024

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.

Next Article: Implementing Private Messaging in a WebSocket Chat Application in Go

Previous Article: Using WebSockets with Channels for Concurrent Communication in Go

Series: Websocket & Chat Programs in Go

Golang

Related Articles

You May Also Like

  • How to remove HTML tags in a string in Go
  • How to remove special characters in a string in Go
  • How to remove consecutive whitespace in a string in Go
  • How to count words and characters in a string in Go
  • Relative imports in Go: Tutorial & Examples
  • How to run Python code with Go
  • How to generate slug from title in Go
  • How to create an XML sitemap in Go
  • How to redirect in Go (301, 302, etc)
  • Using Go with MongoDB: CRUD example
  • Auto deploy Go apps with CI/ CD and GitHub Actions
  • Fixing Go error: method redeclared with different receiver type
  • Fixing Go error: copy argument must have slice type
  • Fixing Go error: attempted to use nil slice
  • Fixing Go error: assignment to constant variable
  • Fixing Go error: cannot compare X (type Y) with Z (type W)
  • Fixing Go error: method has pointer receiver, not called with pointer
  • Fixing Go error: assignment mismatch: X variables but Y values
  • Fixing Go error: array index must be non-negative integer constant