# Build a websocket server using express & ws package

This is yet another kind of NodeJs websocket tutorial that i was hoping to talk about my experience in building a websocket server and implementing a pub/sub pattern to send and receive events the same way `socket.io` is providing but we here we're using the simple to use and blazing fast `ws` package.

## Why not socket.io?

Well first it has all you might need, and i mean all like all of it, which is kinda a lot since you end up using a lot of stuff you don't actually need, while on the other hand `ws` provides you with the base functionality and the ability to customize it as per needs

 Besides i remember times when `socket.io` repository was abandoned, and they had a lot of issues, and they it was kinda deprecated in favor of `engine.io` and made a great role also in choosing `ws` over it.

## HTTP server setup

Now let's setup our express HTTP server a typical implementation with nothing fancy

```jsx
const express = require('express')
const app = express()
const PORT = 3000 || process.env.PORT

app.get('/', (_, res) => {
  res.send('Welcome to main page')
})

app.listen(PORT, () => {
  console.log(`Server is working on http://localhost:${PORT}`)
})
```

Nothing special here, we defined our index endpoint which is going to return `Welcome to main page` if we went to [http://localhost:3000/](http://localhost:3000/)

So to setup our websocket server we need to import `ws` package and then tweak this a little bit

```jsx
const express = require('express')
const WsServer = require('ws')
const { createServer } = require('http')

const app = express()
const server = createServer(app)

function initWs() {
  const options = {
    noServer: true
  }

  return new WsServer.Server(options)
}

function initHttpServer(port) {
  app.set('view engine', 'ejs')

  app.get('/', (_, res) => {
    res.render('index')
  })

  server.listen(port, () => {
    console.log(`Server is working on http://localhost:${port}`)
  })

  return app
}

function initWebSocketServer(port = 3000) {
  initHttpServer(port)
  const wss = initWs()

  server.on('upgrade', async(req, socket, head) => {
    try {
      wss.handleUpgrade(req, socket, head, (ws) => {
        // Do something before firing the connected event

        wss.emit('connection', ws, req)
      })
    } catch(err) {
      // Socket uprade failed
      // Close socket and clean
      console.log('Socket upgrade failed', err)
      socket.destroy()
    }
  })

  return wss
}

const wss = initWebSocketServer()

wss.on('connection', (ws) => {
  ws.on('message', (data) => {
    ws.send(data)
  })
})
```

Now we splitted the code into 3 functions, 1 to handle preparing our websocket headless server by just passing `noServer: true` to ws server constructor, beside a function to setup our http server and notice that we added new route 

```jsx
  app.get('/', (_, res) => {
    res.render('index')
  })
```

This to handle our client that is going to be connected to our server and thats where our client code will live on `index` view, where it exists under `views` directory here

```jsx
websocket-server/
├─ views/
│  ├─ index.ejs
├─ server.js
```

## Client side setup

Now on the client side the code is pretty simple

```jsx
<!DOCTYPE html>
<html lang="en">
  <head>
    <title>WS Test</title>
  </head>
  <body class="container">
    <script>
      let keepAliveId = null
      function connect({ url, keepAlive, keepAlivePeriod }) {
        const ws = new WebSocket(url)

        if (keepAlive) {
          clearInterval(keepAliveId)
          keepAliveId = setInterval(() => {
            ws.send('ping')
          }, keepAlivePeriod || 5000)
        }

        ws.onopen = () => {
          console.log('Websocket is open')
        }

        ws.onclose = () => {
          console.log('Websocket closed')
        }

        ws.onerror = (err) => {
          console.log('Websocket error', err)
        }

        ws.onmessage = (message) => {
          console.log('Websocket data', message.data)
        }
      }

      connect({
        url: 'ws://localhost:3000',
        keepAlive: true,
        keepAlivePeriod: 5000
      })
    </script>
  </body>
</html>
```

We have our connect function here that expects the following options `{ url, keepAlive, keepAlivePeriod }`

`keepAlive` property is to keep the websocket connection alive by sending message after a period of milliseconds which what in the `keepAlivePeriod` for

The way we're keeping the websocket alive is in this snippet

```jsx
        if (keepAlive) {
          clearInterval(keepAliveId)
          keepAliveId = setInterval(() => {
            ws.send('ping')
          }, keepAlivePeriod || 5000)
        }
```

So every period of time we're sending this ping message to server and thus server is going to echo back what we're sending and this is how simply the socket connection is alive 

That’s basically how we created a simple echo server using just `ws` package with even the ability to keep the socket connection alive. Later on I will explain how to trigger events from client side and even subscribe to these events so whenever server is emitting an event it will be received by the client
