How to Create a Chat App With Bun Using WebSockets
Published: 2023-09-30 06:02:32

Lets Create a Bun Server

`bun init`

Just press enter.. enter..

![bun1](https://eneaslari.com/e20503e2-3057-415e-a747-a44dc4c6e47d.PNG "bun")

Run the file 

```bash
bun run index.ts`
```

### Implementing WebSockets in JavaScript

Let’s create a simple WebSocket connection in JavaScript. Firstly, ensure your server supports WebSocket connections.

```javascript
// Creating a new WebSocket instance
const socket = new WebSocket('ws://your-websocket-server.com');

// Connection opened
socket.addEventListener('open', (event) => {
    socket.send('Hello Server!');
});

// Listen for messages
socket.addEventListener('message', (event) => {
    console.log('Message from server:', event.data);
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
```

In this snippet:

1. We create a new `WebSocket` instance, passing the WebSocket server URL.
2. We attach an event listener for the `open` event, which triggers when the connection is established, sending a greeting to the server.
3. We listen for any messages from the server with the `message` event.
4. Finally, we have a listener for the `close` event, which triggers when the connection is closed.


Let's Build a simple WebSocket server with Bun

First rename index.ts to server.ts

index.ts

```javascript
const server = Bun.serve({
    port: 8080,
    fetch(req, server) {
        // upgrade the request to a WebSocket
        if (server.upgrade(req)) {
            return; // do not return a Response
        } 
        return new Response("Upgrade failed :(", { status: 500 });
    }, // upgrade logic
    websocket: {
        async message(ws, message) {
            console.log("Message was received from server:",message)
            ws.send("I received your message")
        }, // a message is received
        open(ws) {
            console.log("Connection opened")
        }, // a socket is opened
        close(ws, code, message) {
            console.log("Connection closed")
        }, // a socket is closed
        drain(ws) {}, // the socket is ready to receive more data
    },
  });

  console.log(`Listening on ${server.hostname}:${server.port}`);
```


Now, to start your server, run the following command in the terminal:

```bash
bun run server.ts
```

### Creating Chat Room

First let's create a client's UI (a html page)

index.html

```xml
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebSocket client</title>
  </head>
  <body>
    <button id="sendmessagebutton">Broadcast Message</button>
    <button id="sendtoserver">Send Message to server</button>
    <p id="logging">Logging:</p>
    <script src="client.js"></script>
  </body>
</html>

```

- The "Broadcast Message" button is for sending a message for broadcasting
- The "Send message to server" is for sending message only to server
- The paragraph is for logging things on the client

Now let's change a little bit the client.js

```javascript
// Creating a new WebSocket instance
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', (event) => {
    var sayhi = {
        "type": "SENDTOSERVER",
        "payload": {
            "message": "Hello server, How are you?"
        }
    }
    socket.send(JSON.stringify(sayhi));
    document.getElementById("logging").innerText += "\n" + "You sent this mesage to the server: " + sayhi.payload.message

    document.getElementById("sendmessagebutton").addEventListener("click", () => {
        var newmessage = {
            "type": "BROADCAST",
            "payload": {
                "author": "A USER",
                "message": "Hi everyone!"
            }
        }
        socket.send(JSON.stringify(newmessage))
        document.getElementById("logging").innerText += "\n" + "You sent this mesage for broadcasting to the server: " + newmessage.payload.message
    })
    document.getElementById("sendtoserver").addEventListener("click", () => {
        var newmessage = {
            "type": "SENDTOSERVER",
            "payload": {
                "author": "A USER",
                "message": "This message is for server only"
            }
        }
        socket.send(JSON.stringify(newmessage))
    })
});

// Listen for messages
socket.addEventListener('message', (event) => {
    try {
        var message = JSON.parse(event.data);
        if (message.type === 'BROADCAST') {
            document.getElementById("logging").innerText += "\n" + "A client broadcasted: " + message.payload.message
        } else {
            document.getElementById("logging").innerText += "\n" + "You received this message: " + message.payload.message
        }

    } catch (e) {
        console.log('Wrong format');
        return;
    }
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
```

We will change the server so it can differentiate the messages that are for broadcasting and for server only.

```javascript
const wsserver = Bun.serve({
    port: 8080,
    fetch(req, server) {
        // upgrade the request to a WebSocket
        if (server.upgrade(req)) {
            return; // do not return a Response
        }
        return new Response("Upgrade failed :(", { status: 500 });
    }, // upgrade logic
    websocket: {
        async message(ws, msg) {
            console.log("Message was received from server:", msg)
            var message;
            try {
                message = JSON.parse(msg.toString());

            } catch (e) {
                console.log('Wrong format');
                return;
            }

            if (message.type === 'BROADCAST') {
                // Broadcast the message to all connected clients
                var newmessage = {
                    "type": "BROADCAST",
                    "payload": {
                        "author": "Server",
                        "message": message.payload.message
                    }
                }
                ws.publish("chat",JSON.stringify(newmessage))
            }
            if (message.type === 'SENDTOSERVER') {
                var respond = {
                    "type": "SERVER_MESSAGE",
                    "payload": {
                        "author": "Server",
                        "message": "I received your message:<<" + message.payload.message + ">>"
                    }
                }
                ws.send(JSON.stringify(respond));
            }




        }, // a message is received
        async open(ws) {
            ws.subscribe("chat")
            console.log("Connection opened and you subscribed on chat")
        }, // a socket is opened
        async close(ws, code, message) {
            console.log("Connection closed")
        }, // a socket is closed
        async drain(ws) { }, // the socket is ready to receive more data
    },
});

console.log(`Listening on ${wsserver.hostname}:${wsserver.port}`);
```

Let's test things:

run `node server.js`

Then press the Go Live button on visual studio code to fire up a client

![websocket](https://eneaslari.com/2994a6b2-fe77-45ad-96a1-53374ad5f459.PNG "1")

You should see this:

![websocket](https://eneaslari.com/68160236-8f0b-490a-879d-b4b578b7dc0d.PNG "1")

If you open a second tab you will connect a second client:

![websocket](https://eneaslari.com/75614a1c-6f5b-47df-b56b-f8d64b7329ad.PNG "1")

Then you can broadcast messages(press "Broadcast Message")
The server will receive the message and will broadcast it to the clients (except sender) 

![websocket](https://eneaslari.com/954dfa58-6cb3-4eb5-ab20-a18cb87f57dd.PNG "1")

Also, you can send messages only to the server and get a response

![websocket](https://eneaslari.com/4fa86f3a-35d5-428a-b67e-f86dba9994a0.PNG "1")

That's for now!

You can find the code of this article here : [GitHub Repository](https://github.com/EneasLari/how-to-create-a-chat-app-with-bun-using-websockets "GitHub")

Sources 

[bun.sh  Set per-socket contextual data on a WebSocket with Bun](https://bun.sh/guides/websocket/context "nameforurl")

[bun.sh WebSockets](https://bun.sh/docs/api/websockets "nameforurl")

[bun.sh Build a simple WebSocket server with Bun](https://bun.sh/guides/websocket/simple "nameforurl")

[Create a chat application with Bun JavaScript runtime](https://www.youtube.com/watch?v=PHrFCor8Jb8&ab_channel=monroeprograms "nameforurl")