Creating a Chat Application with Go, Gorilla WebSocket, and jQuery
In this blog, we will explore how to build a real-time chat application using Go (Golang), Gorilla WebSocket, and jQuery. Real-time chat applications require quick and seamless communication between users, and WebSockets make this possible by enabling continuous, two-way communication.
Why WebSockets?
WebSockets are an advanced technology that allows a persistent, bidirectional connection between the client (e.g., browser) and the server. Unlike traditional HTTP, where a connection is opened for each request and response, WebSockets establish a single connection that remains open throughout the session. This reduces overhead and ensures low-latency communication.
WebSocket Workflow
The WebSocket protocol works as shown in the diagram:
HTTP Connection (Upgrade Request):
The process begins with a standard HTTP connection where the client sends an "Upgrade" request to the server, asking to switch to the WebSocket protocol.101 Switching Protocols:
If the server supports WebSockets, it responds with an HTTP101 Switching Protocols
status code. This confirms that the connection is upgraded.WebSocket Communication:
Once the connection is upgraded, bidirectional communication starts. Both the client and server can send messages to each other over the same connection without repeatedly re-establishing connections.Connection Close:
When the communication ends, either the client or the server can close the WebSocket connection.
This workflow ensures efficient and fast communication, making WebSockets ideal for applications like chats, live notifications, or real-time updates.
Setting Up the Project
To build a real-time chat application using Go, Gorilla WebSocket, and jQuery, it’s important to set up the project directory structure correctly. Below is the step-by-step guide and methods to include all dependencies and necessary files.
Project Directory Structure
1. Initializing the Project
Start by creating the Go module and installing required dependencies.
- Initialize the Go Module:
Run the following command to initialize a Go module in the project root:
go mod init go-websocket-blog
- Install Dependencies:
Install the necessary libraries:
go get github.com/gorilla/websocket
go get github.com/bmizerany/pat
go get github.com/CloudyKit/jet/v6
2. Adding Reconnecting WebSocket
To include the reconnecting-websocket.min.js
library for automatic reconnections, you can fetch it either automatically (Linux/Mac) or manually (Windows).
Automatic Download (Linux/Mac)
Run the following script to download the file into the correct directory:
#!/bin/bash
# Create required directories
mkdir -p assets/javascript
# Download reconnecting-websocket.min.js
curl -o assets/javascript/reconnecting-websocket.min.js \
https://raw.githubusercontent.com/joewalnes/reconnecting-websocket/master/reconnecting-websocket.min.js
echo "reconnecting-websocket.min.js has been downloaded successfully!"
Manual Download (Windows)
Go to the following URL:
https://github.com/joewalnes/reconnecting-websocket/blob/master/reconnecting-websocket.min.jsCopy the entire code from the file.
Create a file named
reconnecting-websocket.min.js
inside theassets/javascript/
directory.Paste the copied code into the file and save it.
3. Full Bash Script to Generate the Project Structure
To automate the entire setup, use the following script:
#!/bin/bash
# Create project structure
mkdir -p go-websocket-blog/assets/css
mkdir -p go-websocket-blog/assets/javascript
mkdir -p go-websocket-blog/cmd
mkdir -p go-websocket-blog/pkg/handlers
mkdir -p go-websocket-blog/pkg/routes
mkdir -p go-websocket-blog/templates
cd go-websocket-blog
# Create files
touch assets/css/styles.css
touch assets/javascript/main.js
touch cmd/main.go
touch pkg/handlers/handlers.go
touch pkg/routes/routes.go
touch templates/home.html
# Initialize Go module
go mod init go-websocket-blog
# Add dependencies
go get github.com/gorilla/websocket
go get github.com/bmizerany/pat
go get github.com/CloudyKit/jet/v6
# Fetch reconnecting-websocket.min.js
curl -o assets/javascript/reconnecting-websocket.min.js \
https://raw.githubusercontent.com/joewalnes/reconnecting-websocket/master/reconnecting-websocket.min.js
# Print success message
echo "Project structure created successfully with dependencies and reconnecting-websocket!"
Core WebSocket Handlers
The handlers.go
file serves as the heart of this application, managing WebSocket connections, communication, and rendering templates. We'll break down the code function by function, explaining its purpose and behavior. Let’s get started!
Setting Up WebSocket Connections and Templates
var (
wsChannel = make(chan WsPayload)
clients = make(map[*websocket.Conn]string)
views = jet.NewSet(
jet.NewOSFileSystemLoader("./templates"),
jet.InDevelopmentMode(),
)
upgradeConnection = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}
)
Explanation:
wsChannel
: A Go channel for passing messages between WebSocket handlers.clients
: A map to track active WebSocket connections and their associated usernames.views
: Configures Jet template engine to load templates from the./templates
directory.upgradeConnection
: Configures WebSocket settings, allowing all origins (CheckOrigin
returnstrue
).
This setup enables managing WebSocket connections and rendering HTML templates dynamically.
Home Page Handler
func Home(w http.ResponseWriter, r *http.Request) {
log.Println("Rendering home page")
err := renderPage(w, "home.html", nil)
if err != nil {
log.Println("Error rendering home page:", err)
}
}
Explanation:
The
Home
function renders thehome.html
template using therenderPage
helper function.If rendering fails, it logs the error. This provides a simple way to serve the application's main interface.
WebSocket Endpoint
func WsEndpoint(w http.ResponseWriter, r *http.Request) {
log.Println("Client attempting to connect to WebSocket endpoint")
ws, err := upgradeConnection.Upgrade(w, r, nil)
if err != nil {
log.Println("WebSocket upgrade failed:", err)
return
}
log.Println("Client successfully connected to WebSocket endpoint")
response := WsJsonResponse{
Message: "<em><small>Connected to server</small></em>",
}
clients[ws] = ""
err = ws.WriteJSON(response)
if err != nil {
log.Println("Error writing JSON response:", err)
return
}
go ListenForWs(ws)
}
Explanation:
Upgrade Connection: Converts an HTTP connection into a WebSocket connection using
websocket.Upgrader
.Initial Response: Sends a confirmation message to the client.
Client Management: Adds the WebSocket connection to the
clients
map.Message Listening: Launches the
ListenForWs
function in a goroutine to handle client messages asynchronously.
Listening to Client Messages
func ListenForWs(conn *websocket.Conn) {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from error: %v", r)
}
}()
var payload WsPayload
for {
if err := conn.ReadJSON(&payload); err != nil {
log.Println("Error reading WebSocket message:", err)
return
}
payload.Conn = conn
wsChannel <- payload
}
}
Explanation:
Reads JSON messages from the client and stores them in the
payload
.Adds the client’s connection to the
payload
and sends it towsChannel
for processing.Uses
defer
to gracefully handle panics and clean up.
Handling Messages on the WebSocket Channel
func ListenToWsChannel() {
for {
e := <-wsChannel
var response WsJsonResponse
switch e.Action {
case "username":
clients[e.Conn] = e.Username
response.Action = "list_users"
response.ConnectedUsers = getUserList()
broadcastToAll(response)
case "left":
delete(clients, e.Conn)
response.Action = "list_users"
response.ConnectedUsers = getUserList()
broadcastToAll(response)
case "broadcast":
response.Action = "broadcast"
response.Message = fmt.Sprintf("<strong>%s</strong>: %s", e.Username, e.Message)
broadcastToAll(response)
}
}
}
Explanation:
Listening to
wsChannel
: Continuously waits for messages sent through the channel.Message Handling:
username
: Updates the client's username and broadcasts the user list.left
: Removes a client and updates the user list.broadcast
: Sends the client’s message to all connected users.
Helper Functions
Retrieve User List
func getUserList() []string {
var userList []string
for _, username := range clients {
if username != "" {
userList = append(userList, username)
}
}
sort.Strings(userList)
return userList
}
Purpose: Collects all usernames from clients
, sorts them alphabetically, and returns the list.
Broadcast Messages
func broadcastToAll(response WsJsonResponse) {
for client := range clients {
if err := client.WriteJSON(response); err != nil {
log.Printf("Error sending message to client: %v", err)
_ = client.Close()
delete(clients, client)
}
}
}
Purpose: Sends a JSON response to all connected WebSocket clients. Removes clients that fail to receive the message.
Render Templates
func renderPage(w http.ResponseWriter, tmpl string, data jet.VarMap) error {
view, err := views.GetTemplate(tmpl)
if err != nil {
log.Println("Error loading template:", err)
return err
}
if err := view.Execute(w, data, nil); err != nil {
log.Println("Error executing template:", err)
return err
}
return nil
}
Purpose: Fetches and renders an HTML template with dynamic data using Jet.
Here’s the complete handlers.go
file for you to copy and use
package handlers
import (
"fmt"
"log"
"net/http"
"sort"
"github.com/CloudyKit/jet/v6"
"github.com/gorilla/websocket"
)
// Global variables for managing WebSocket connections
var (
wsChannel = make(chan WsPayload) // Channel for handling WebSocket messages
clients = make(map[*websocket.Conn]string) // Map of connected clients and their usernames
views = jet.NewSet( // Template engine configuration
jet.NewOSFileSystemLoader("./templates"),
jet.InDevelopmentMode(),
)
upgradeConnection = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true }, // Allow all origins
}
)
// Home renders the home page of the application
func Home(w http.ResponseWriter, r *http.Request) {
log.Println("Rendering home page")
err := renderPage(w, "home.html", nil)
if err != nil {
log.Println("Error rendering home page:", err)
}
}
// WsJsonResponse represents the JSON structure for WebSocket responses
type WsJsonResponse struct {
Action string `json:"action"`
Message string `json:"message"`
MessageType string `json:"message_type"`
ConnectedUsers []string `json:"connected_users"`
}
// WsPayload represents the payload received from WebSocket clients
type WsPayload struct {
Action string `json:"action"`
Username string `json:"username"`
Message string `json:"message"`
Conn *websocket.Conn `json:"-"` // Exclude from JSON serialization
}
// WsEndpoint upgrades HTTP connections to WebSocket and initializes communication
func WsEndpoint(w http.ResponseWriter, r *http.Request) {
log.Println("Client attempting to connect to WebSocket endpoint")
ws, err := upgradeConnection.Upgrade(w, r, nil)
if err != nil {
log.Println("WebSocket upgrade failed:", err)
return
}
log.Println("Client successfully connected to WebSocket endpoint")
// Initial connection response
response := WsJsonResponse{
Message: "<em><small>Connected to server</small></em>",
}
clients[ws] = "" // Add the new connection to clients map
err = ws.WriteJSON(response)
if err != nil {
log.Println("Error writing JSON response:", err)
return
}
// Start listening for messages from this client
go ListenForWs(ws)
}
// ListenToWsChannel listens for messages on the WebSocket channel and handles them
func ListenToWsChannel() {
for {
e := <-wsChannel
var response WsJsonResponse
switch e.Action {
case "username":
// Handle username assignment
clients[e.Conn] = e.Username
response.Action = "list_users"
response.ConnectedUsers = getUserList()
broadcastToAll(response)
case "left":
// Handle client disconnection
response.Action = "list_users"
delete(clients, e.Conn)
response.ConnectedUsers = getUserList()
broadcastToAll(response)
case "broadcast":
// Handle broadcast messages
response.Action = "broadcast"
response.Message = fmt.Sprintf("<strong>%s</strong>: %s", e.Username, e.Message)
broadcastToAll(response)
}
}
}
// getUserList returns a sorted list of connected usernames
func getUserList() []string {
var userList []string
for _, username := range clients {
if username != "" {
userList = append(userList, username)
}
}
sort.Strings(userList)
return userList
}
// broadcastToAll sends a WebSocket response to all connected clients
func broadcastToAll(response WsJsonResponse) {
for client := range clients {
if err := client.WriteJSON(response); err != nil {
log.Printf("Error sending message to client: %v", err)
_ = client.Close()
delete(clients, client)
}
}
}
// ListenForWs listens for messages from a specific WebSocket client
func ListenForWs(conn *websocket.Conn) {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from error: %v", r)
}
}()
var payload WsPayload
for {
if err := conn.ReadJSON(&payload); err != nil {
log.Println("Error reading WebSocket message:", err)
return
}
// Assign connection to payload and send it to the channel
payload.Conn = conn
wsChannel <- payload
}
}
// renderPage renders a template with the given data
func renderPage(w http.ResponseWriter, tmpl string, data jet.VarMap) error {
view, err := views.GetTemplate(tmpl)
if err != nil {
log.Println("Error loading template:", err)
return err
}
if err := view.Execute(w, data, nil); err != nil {
log.Println("Error executing template:", err)
return err
}
return nil
}
Now that we’ve covered the core functionality in handlers.go
, let’s look at how the routing and server setup are handled in routes.go
and main.go
. These files configure the application’s routes and initialize the server.
Application Routing
routes.go
package routes
import (
"net/http"
"github.com/arya2004/gobanter/pkg/handlers"
"github.com/bmizerany/pat"
)
func Routes() http.Handler {
mux := pat.New()
mux.Get("/", http.HandlerFunc(handlers.Home))
mux.Get("/ws", http.HandlerFunc(handlers.WsEndpoint))
fileServer := http.FileServer(http.Dir("./assets/"))
mux.Get("/assets/", http.StripPrefix("/assets/", fileServer))
return mux
}
Explanation:
Router Initialization:
pat.New
()
creates a new router using thepat
package, which provides a simple pattern-based routing mechanism.
Home Page Route:
- The
"/"
route maps to theHome
handler, which serves the home page.
- The
WebSocket Route:
- The
"/ws"
route is connected to theWsEndpoint
handler, establishing WebSocket communication.
- The
Static File Serving:
Serves static files (e.g., CSS, JS, images) from the
assets
directory usinghttp.FileServer
.http.StripPrefix
removes the/assets/
prefix from the URL path before serving files.
Application Entry Point
main.go
package main
import (
"log"
"net/http"
"github.com/arya2004/gobanter/pkg/handlers"
"github.com/arya2004/gobanter/pkg/routes"
)
func main() {
mux := routes.Routes()
log.Println("Starting WebSocket channel listener...")
go handlers.ListenToWsChannel()
log.Println("Server starting on port 8080...")
if err := http.ListenAndServe(":8080", mux); err != nil {
log.Fatalf("Error starting server: %v", err)
}
}
Explanation:
Initialize Routes:
- The
routes.Routes()
function sets up all application routes and returns ahttp.Handler
.
- The
WebSocket Channel Listener:
handlers.ListenToWsChannel()
is launched in a goroutine to handle WebSocket messages asynchronously.
Start HTTP Server:
The server listens on port
8080
usinghttp.ListenAndServe
with the router (mux
) handling incoming requests.Logs errors if the server fails to start.
User Interface for Chat Application
This HTML file defines the structure of the chat application's user interface. It includes the layout for sending messages, displaying the chat history, and listing online users. It uses Bootstrap for styling and incorporates custom CSS and JavaScript for functionality. The file is loaded as the home page of the application.
Copy and paste the above code into an home.html
file in your project for the chat application interface.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Chat Application</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
<link rel="stylesheet" href="/assets/css/styles.css">
</head>
<body>
<div class="container mt-5">
<header class="text-center mb-4">
<h1 class="display-4 fw-bold">Welcome to <span class="text-primary">GoBanter</span></h1>
<p class="text-muted fs-5">Connect and communicate with ease</p>
<hr class="mt-4">
</header>
<div class="row">
<div class="col-md-8">
<div class="card shadow">
<div class="card-header bg-primary text-white">
<div class="chat-header">Chat</div>
</div>
<div class="card-body">
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" id="username" class="form-control" placeholder="Enter your username">
</div>
<div class="mb-3">
<label for="message" class="form-label">Message</label>
<input type="text" id="message" class="form-control" placeholder="Type your message">
</div>
<div class="d-flex justify-content-between">
<button id="sendButton" class="btn btn-primary">Send Message</button>
<div id="status"></div>
</div>
<div id="output" class="chatbox mt-3"></div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card shadow">
<div class="card-header bg-secondary text-white">
<div class="chat-header">Who's Online</div>
</div>
<div class="card-body">
<ul id="online_users"></ul>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.7.1.slim.min.js"
integrity="sha256-kmHvs0B+OpCW5GVHUNjv9rOmY0IvSIRcf7zGUDTDQM8=" crossorigin="anonymous"></script>
<script src="/assets/javascript/reconnecting-websocket.min.js"></script>
<script src="/assets/javascript/main.js"></script>
</body>
</html>
Chat Application Styling
This CSS file defines the styles for the chat application, enhancing the layout and user interface elements. It includes styling for the chatbox, headers, and online user list. Use this file to ensure your application has a clean and responsive design.
Copy the code below and save it as styles.css
:
.chatbox {
border: 1px solid #ddd;
border-radius: 0.5rem;
min-height: 200px;
max-height: 400px;
overflow-y: auto;
padding: 1em;
background-color: #f8f9fa;
}
.chat-header {
font-size: 1.5rem;
font-weight: bold;
}
#online_users {
list-style: none;
padding: 0;
}
#online_users li {
background: #e9ecef;
margin-bottom: 0.5em;
padding: 0.5em;
border-radius: 0.5rem;
}
jQuery-Powered WebSocket Communication
This main.js
file contains the client-side logic for interacting with the WebSocket server using jQuery. It includes functions to handle WebSocket events, update the UI dynamically, and manage user interactions. Below, we’ll break the code into sections and explain each part.
WebSocket Initialization
let socket = null;
$(document).ready(function () {
const offline = `<span class="badge bg-danger">Not connected</span>`;
const online = `<span class="badge bg-success">Connected</span>`;
const $statusDiv = $("#status");
const $output = $("#output");
const $userField = $("#username");
const $messageField = $("#message");
const $onlineUsers = $("#online_users");
socket = new ReconnectingWebSocket("ws://localhost:8080/ws", null, { debug: true, reconnectInterval: 3000 });
Explanation:
Variables:
offline
andonline
: HTML badges indicating connection status.$statusDiv
,$output
,$userField
,$messageField
,$onlineUsers
: Cached jQuery selectors for UI elements.
WebSocket Connection:
ReconnectingWebSocket
is used to establish a persistent WebSocket connection with auto-reconnect enabled.
Handling WebSocket Events
socket.onopen = function () {
console.log("connected!!");
$statusDiv.html(online);
};
socket.onclose = function () {
console.log("connection closed!");
$statusDiv.html(offline);
};
socket.onerror = function () {
console.log("there was an error");
$statusDiv.html(offline);
};
Explanation:
onopen
: Updates the UI to show a "Connected" status when the WebSocket connection opens.onclose
: Changes the status to "Not connected" when the connection closes.onerror
: Handles connection errors by logging them and updating the UI.
Receiving WebSocket Messages
socket.onmessage = function (msg) {
const data = JSON.parse(msg.data);
console.log("Action:", data.action);
switch (data.action) {
case "list_users":
$onlineUsers.empty();
if (data.connected_users.length > 0) {
$.each(data.connected_users, function (index, user) {
$onlineUsers.append(`<li class="list-group-item">${user}</li>`);
});
}
break;
case "broadcast":
$output.append(`<div>${data.message}</div>`);
$output.scrollTop($output.prop("scrollHeight"));
break;
}
};
Explanation:
onmessage
:Parses incoming WebSocket messages as JSON.
Switch Cases:
list_users
: Updates the "Who's Online" list with connected usernames.broadcast
: Appends broadcast messages to the chatbox and scrolls to the latest message.
User Interaction: Username Update
$userField.on("change", function () {
const jsonData = {
action: "username",
username: $(this).val()
};
console.log(jsonData);
socket.send(JSON.stringify(jsonData));
});
Explanation:
Listens for changes in the username field.
Sends a
username
action to the server with the new username as JSON.
Sending Messages
$messageField.on("keydown", function (event) {
if (event.key === "Enter") {
if (!socket || socket.readyState !== WebSocket.OPEN) {
alert("No connection");
return false;
}
if (!$userField.val() || !$messageField.val()) {
alert("Enter username and message!");
return false;
} else {
sendMessage();
}
event.preventDefault();
}
});
$("#sendButton").on("click", function () {
if (!$userField.val() || !$messageField.val()) {
alert("Enter username and message!");
return false;
} else {
sendMessage();
}
});
Enter Key:
Triggers
sendMessage
when Enter is pressed in the message field.Validates that a username and message are provided and checks WebSocket connection status.
Send Button:
- Performs the same validation and triggers
sendMessage
when the "Send Message" button is clicked.
- Performs the same validation and triggers
Disconnecting on Page Unload
$(window).on("beforeunload", function () {
console.log("leaving ;(");
if (socket && socket.readyState === WebSocket.OPEN) {
const jsonData = { action: "left" };
socket.send(JSON.stringify(jsonData));
}
});
Explanation:
Listens for the browser's
beforeunload
event (e.g., closing the tab or refreshing the page).Sends a
left
action to notify the server that the user has disconnected.
Sending JSON Data to WebSocket
function sendMessage() {
const jsonData = {
action: "broadcast",
username: $userField.val(),
message: $messageField.val()
};
socket.send(JSON.stringify(jsonData));
$messageField.val("");
}
Explanation:
Constructs a JSON object with the
broadcast
action, username, and message.Sends the JSON to the server through the WebSocket connection.
Clears the message field after sending.
Full Code
Here’s the full main.js
file without comments for you to copy and use:
let socket = null;
$(document).ready(function () {
const offline = `<span class="badge bg-danger">Not connected</span>`;
const online = `<span class="badge bg-success">Connected</span>`;
const $statusDiv = $("#status");
const $output = $("#output");
const $userField = $("#username");
const $messageField = $("#message");
const $onlineUsers = $("#online_users");
// Reconnecting WebSocket Initialization
socket = new ReconnectingWebSocket("ws://localhost:8080/ws", null, { debug: true, reconnectInterval: 3000 });
// WebSocket Events
socket.onopen = function () {
console.log("connected!!");
$statusDiv.html(online);
};
socket.onclose = function () {
console.log("connection closed!");
$statusDiv.html(offline);
};
socket.onerror = function () {
console.log("there was an error");
$statusDiv.html(offline);
};
socket.onmessage = function (msg) {
const data = JSON.parse(msg.data);
console.log("Action:", data.action);
switch (data.action) {
case "list_users":
$onlineUsers.empty();
if (data.connected_users.length > 0) {
$.each(data.connected_users, function (index, user) {
$onlineUsers.append(`<li class="list-group-item">${user}</li>`);
});
}
break;
case "broadcast":
$output.append(`<div>${data.message}</div>`);
$output.scrollTop($output.prop("scrollHeight"));
break;
}
};
// Username Field Change
$userField.on("change", function () {
const jsonData = {
action: "username",
username: $(this).val()
};
console.log(jsonData);
socket.send(JSON.stringify(jsonData));
});
// Message Field Enter Key
$messageField.on("keydown", function (event) {
if (event.key === "Enter") {
if (!socket || socket.readyState !== WebSocket.OPEN) {
alert("No connection");
return false;
}
if (!$userField.val() || !$messageField.val()) {
alert("Enter username and message!");
return false;
} else {
sendMessage();
}
event.preventDefault();
}
});
// Send Button Click
$("#sendButton").on("click", function () {
if (!$userField.val() || !$messageField.val()) {
alert("Enter username and message!");
return false;
} else {
sendMessage();
}
});
// WebSocket Disconnect on Page Unload
$(window).on("beforeunload", function () {
console.log("leaving ;(");
if (socket && socket.readyState === WebSocket.OPEN) {
const jsonData = { action: "left" };
socket.send(JSON.stringify(jsonData));
}
});
// Function to Send Message
function sendMessage() {
const jsonData = {
action: "broadcast",
username: $userField.val(),
message: $messageField.val()
};
socket.send(JSON.stringify(jsonData));
$messageField.val("");
}
});
Conclusion
Building a real-time chat application using Go, Gorilla WebSocket, and jQuery is a great way to explore modern web development with WebSocket-based communication. By combining a robust backend in Go with jQuery on the frontend, you can achieve a seamless and interactive user experience.
The chat application features a user-friendly design as shown below:
This simple chat application demonstrates real-time user updates, message broadcasting, and client-server communication. To access the full source code and dive deeper into the implementation, visit the GitHub repository: https://github.com/arya2004/gobanter.
Happy coding!