The complete code for this section: GitHub

This article is the second in a series on building chat applications using ReactJS and Go. You can find part 1 – Initialization Settings here

Now that we have the basic front and back ends in place, it’s time to refine some features.

In this section, we will implement a Websocket-based server.

By the end of this series of tutorials, we will have a front-end application that can communicate bidirectional with the back end.

service

We can use github.com/gorilla/websocket package to set the WebSocket service and processing connection will read and write operations.

This requires running this command in our backend/ directory to install it:

$ go get github.com/gorilla/websocket
Copy the code

Once we have successfully installed this package, we can start building our Web service. Let’s start by creating a very simple NET/HTTP service:

package main

import (
    "fmt"
    "net/http"
)

func setupRoutes(a) {
    http.HandleFunc("/".func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Simple Server")})}func main(a) {
    setupRoutes()
    http.ListenAndServe(": 8080".nil)}Copy the code

The service can be started by calling go Run main.go, which listens on http://localhost:8080. If you open this connection with a browser, you can see Simple Server output.

The WebSocket protocol

Before we start writing code, we need to understand the theory.

WebSockets allow duplex communication over TCP connections. This allows us to send and listen for messages over a single TCP socket, avoiding the need to poll the Web server to communicate, where the TCP handshake process is performed for each polling operation.

WebSockets significantly reduce the network bandwidth required by applications and allow us to maintain a large number of clients on a single server instance.

The connection

WebSockets certainly have some drawbacks worth considering. For example, once state is introduced, it becomes more complex when extending an application across multiple instances.

There are more scenarios to consider in this scenario, such as storing state in a message broker or in a database/memory cache.

implementation

To implement the WebSocket service, we need to create an endpoint and then upgrade the connection of that endpoint from standard HTTP to WebSocket.

Thankfully, the Gorilla/WebSocket package provides the functionality we need to easily upgrade HTTP connections to WebSocket connections.

Note – you can check out the official WebSocket protocol for more information: RFC-6455

Create a WebSocket server

Now that you know the theory, let’s see how to put it into practice. We create a new endpoint/WS that we will convert from a standard HTTP endpoint to a WS endpoint.

This endpoint does three things, it checks for incoming HTTP requests, and then returns true to open our endpoint to the client. Then, we upgrade to a WebSocket connection using the defined upgrader.

Finally, we’ll start listening for incoming messages, then print them out and send them back to the same connection. This allows us to validate the front end connection and send/receive messages from the newly created WebSocket endpoint:

package main

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

    "github.com/gorilla/websocket"
)

// We need to define a Upgrader
// It needs to define ReadBufferSize and WriteBufferSize
var upgrader = websocket.Upgrader{
    ReadBufferSize:  1024,
  WriteBufferSize: 1024.// Can be used to check the source of the connection
  // This will allow requests to be made here from our React service.
  // Now we can run any connections without checking them
  CheckOrigin: func(r *http.Request) bool { return true}},// Define a reader to listen for new messages sent to the WS
func reader(conn *websocket.Conn) {
    for {
    / / read the message
        messageType, p, err := conn.ReadMessage()
        iferr ! =nil {
            log.Println(err)
            return
        }
    // Prints the message
        fmt.Println(string(p))

        iferr := conn.WriteMessage(messageType, p); err ! =nil {
            log.Println(err)
            return}}}// Define the WebSocket service handler
func serveWs(w http.ResponseWriter, r *http.Request) {
    fmt.Println(r.Host)

  // Update the connection to a WebSocket connection
    ws, err := upgrader.Upgrade(w, r, nil)
    iferr ! =nil {
        log.Println(err)
  }

  // Always listen for new messages from WebSocket connections
    reader(ws)
}

func setupRoutes(a) {
  http.HandleFunc("/".func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Simple Server")})// Pass the '/ws' endpoint to the' serveWs' function for processing
    http.HandleFunc("/ws", serveWs)
}

func main(a) {
    fmt.Println("Chat App v0.01")
    setupRoutes()
    http.ListenAndServe(": 8080".nil)}Copy the code

If there are no problems, we use go Run main.go to start the service.

The client

Now that the service is set up, we need something to interact with it. This is where our ReactJS front end comes in.

Let’s first keep the client simple and define an API /index.js file that will contain the code for the WebSocket connection.

// api/index.js
var socket = new WebSocket("ws://localhost:8080/ws");

let connect = (a)= > {
  console.log("Attempting Connection...");

  socket.onopen = (a)= > {
    console.log("Successfully Connected");
  };

  socket.onmessage = msg= > {
    console.log(msg);
  };

  socket.onclose = event= > {
    console.log("Socket Closed Connection: ", event);
  };

  socket.onerror = error= > {
    console.log("Socket Error: ", error);
  };
};

let sendMsg = msg= > {
  console.log("sending msg: ", msg);
  socket.send(msg);
};

export { connect, sendMsg };
Copy the code

So, in the code above, we define the two functions that we export later. These are connect() and sendMsg(MSG).

The first function, connect(), connects to the WebSocket endpoint and listens for events such as a successful connection to onOpen. If it finds any problems, such as a closed connection socket or an error, it prints them to the browser console.

The second function, sendMsg(MSG), allows us to use socket.send() to send messages from the front end to the back end via a WebSocket connection.

Now we update the app.js file in the React project to add a call to connect() and create a element that triggers the sendMsg() function.

// App.js
import React, { Component } from "react";
import "./App.css";
import { connect, sendMsg } from "./api";

class App extends Component {
  constructor(props) {
    super(props);
    connect();
  }

  send() {
    console.log("hello");
    sendMsg("hello");
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.send}>Hit</button>
      </div>); }}export default App;
Copy the code

After successfully compiling with NPM start, we can see a button in the browser, and if we open the browser console, we can also see that the successfully connected WebSocket service is running at http://localhost:8080.

Question – What happens when you click this button? What output do you see in the browser console and the console at the back?

conclusion

Concludes Part 2 of this series. We’ve been able to create a very simple WebSocket service that can echo any message sent to it.

This was a key step in developing the application, and now that we have the basic framework up and running, we can start thinking about implementing basic chat features and making the application even more useful!

Next section: Part 3 – Front-end implementation


Original text: tutorialedge.net/projects/ch…

Author: Elliot Forbes

This article is originally compiled by GCTT and published by Go Chinese