How to use Golang and React for WebSocket

I found myself wanting to try out little bit of experimenting to learn more about web sockets, let us try it out using golang and react.

First, set up a project Golang project by creating a folder and in it, create main.go file.

Golang WebSocket Server

It’s very simple if you take use of the already great crates that are out there. One that I found working out very well with web socket is gorilla websocket.

package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

func main() {
	http.HandleFunc("/ws", wsEndpoint)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true }
	// upgrade this connection to a WebSocket
	// connection
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	log.Println("Client Connected")
	err = ws.WriteMessage(1, []byte("Hello client you've connected!"))
	if err != nil {
		log.Println(err)
	}
	reader(ws)
}

func reader(conn *websocket.Conn) {
	for {
		// read in a message
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		// print out incoming message
		fmt.Println("incoming message: " + string(p))

		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

You should be able to run your program from the get-go. This is how the mod file looks:

module example.com/m/v2

go 1.15

require github.com/gorilla/websocket v1.5.0 // indirect

http.HandleFunc("/ws", wsEndpoint)

So let’s go through the code, first of all we got a main function, the starting point of the program and in it will first of all take use of the http package and set up our listeners for the endpoint /ws, which we pass in the method wsEndpoint. So each

log.Fatal(http.ListenAndServe(":8080", nil))

The ListenAndServe function will be running our actual http server and we will print out error if we get one into the log.

func wsEndpoint(w http.ResponseWriter, r *http.Request) {
	upgrader.CheckOrigin = func(r *http.Request) bool { return true }
	// upgrade this connection to a WebSocket
	// connection
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	log.Println("Client Connected")
	err = ws.WriteMessage(1, []byte("Hi Client!"))
	if err != nil {
		log.Println(err)
	}
	reader(ws)
}

Our Endpoint function takes in a ResponseWriter and a Request object which is what we need to make to make the incoming request into a websocket protocol connection with our server. This is called that we do an upgrade. From the upgrade function we get back a ws connection which we can read messages from.

func reader(conn *websocket.Conn) {
	for {
		// read in a message
		messageType, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		// print out incoming message
		fmt.Println("incoming message: " + string(p))

		if err := conn.WriteMessage(messageType, p); err != nil {
			log.Println(err)
			return
		}
	}
}

From our reader function we can read the message from the websocket which we convert from bytes into string with help from string(p), which we then can send a response back with WriteMessage on the same socket to the client.

React WebSocket Client

Now let’s create a React project, I like to use vite to get started fast like this:

npm create vite@latest

Then go with React and nativescript. Then what web socket package I use is websocket from here: https://www.npmjs.com/package/websocket. Also remember to download the types for typescript: node_modules/@types/websocket. So we will run npm install on these:

npm i websocket 
npm i node_modules/@types/websocket

Then in our React main.tsx let’s write some code where we connect to the server and send a random message for testing:

import { useEffect, useState } from 'react'
import logo from './logo.svg'
import './App.css'

import * as WebSocket from "websocket"




function App() {

  useEffect(() => {
    console.log("in it")
    const socket = new WebSocket.w3cwebsocket('ws://localhost:8080/ws');

    socket.onopen = function () {
      socket.send("helloheee!")
      socket.onmessage = (msg: any) => {
        console.log(msg);
        console.log("we got msg..")
      };
    };
  }, []);


  const [count, setCount] = useState(0)

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>Hello Vite + React!</p>
        <p>
          <button type="button" onClick={() => setCount((count) => count + 1)}>
            count is: {count}
          </button>
        </p>
        <p>
          Edit <code>App.tsx</code> and save to test HMR updates.
        </p>
        <p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
          {' | '}
          <a
            className="App-link"
            href="https://vitejs.dev/guide/features.html"
            target="_blank"
            rel="noopener noreferrer"
          >
            Vite Docs
          </a>
        </p>
      </header>
    </div>
  )
}

export default App

Also worth noting, inside the main.tsx I removed the StrictMode elements

<React.StrictMode>

if I didn’t it would trigger the user effect twice for some reason. Anyway that’s it to get started fast with a web socket to start experimenting. Hope coding!

5 1 vote
Article rating
Subscribe
Notify of
guest

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Monica Hed Johansson

I like this!

Laychopy
Article rating :
     

So sad that the Gorilla project was archived

FileIdea

yeah I didn’t know, damn, that’s sad indeed.