JavaScript: How to Implement a WebSocket Backend

  • TECH03 — Use WebSockets to Connect Frontend and Backend

Backend Server

npm i -S express socket.io@2.3.0
  • index.js: Implements the express server instance, opening a port at which the websocket connection can be accessed
  • connect.js: Creates a websocket instance by receiving a node HttpServer instance, an object which is e.g. created with express
  • handler.js: The handler defines all websocket events to which and determines how they are processed
  • actions.js: Contains the concrete functions that will be called when a registered event is received, and they return their results to the handler which in turn returns them to the caller.

Webserver with WebSocket Endpoint

//*  index.js *//
const express = require('express')
const websocketConnection = require('./connect.js')
app = express()const httpServer = app.listen(3000, () => {
console.log(`BOOTING | api-blaze-backend v0.0.1`)
})
websocketConnection(httpServer)

Connector

//*  connect.js *//
const websocket = require('socket.io')
const handleConnection = require('./handler.js')
function websocketConnection (httpServer) {
const io = websocket(httpServer, {
serveClient: false
})
io.on('connection', socket => handleConnection(socket))
}
module.exports = websocketConnection

Handler and Actions

//*  handler.js *//
const { apiSearchAction } = require('./actions')
const clients = {}function handleConnection (socket) {
console.log(`+ client ${socket.id} has connected`)
clients[socket.id] = { connected: true }
socket.on('system:healthcheck', msg => {
console.log(msg)
socket.emit('system:healthcheck', 'healthy')
})
socket.on('app:api-search-action', keyword => {
console.log('app:api-search-action', keyword)
socket.emit('app:api-search-action', apiSearchAction(keyword))
})
}
module.exports = handleConnection
//*  action.js *//
const apiInventory = require('./spec/inventory.json')
function apiSearchAction (keyword) {
const regex = new RegExp(keyword, 'ig')
var res = []
for (let [name, definition] of Object.entries(apiInventory)) {
const occurences = JSON.stringify(definition).match(regex)
const score = (occurences && occurences.length) || 0
res.push({ name, score, definition })
}
return res.sort((a, b) => b.score - a.score)
}

Connecting the Frontend

npm i -s snowpack socket.io-client@2.3.0
//*  connect.js (Frontend) *//
import io from 'socket.io-client'
export default io('ws://127.0.0.1:8081', { cookie: false })
import websocket from './globals/connect.js'function init () {
websocket.emit('system:healthcheck', 'ok?')
websocket.on('system:healthcheck', msg => {
console.log(msg)
})
}
init()
import websocket from '../globals/connect.js'export default class SearchApiAction extends Action {
action (cb) {
websocket.emit('app:api-search-action', 'dummy')
websocket.on('app:api-search-action', json => {
cb(json)
})
}
}

Review: ApiBlaze Project Requirements

  • ✅ SEA01 — Search for APIs by Keyword
  • ✅ SEA02 — Show search results in a popup
  • ✅ SEA03 — Select a search results with arrow keys, enter and mouse click
  • ✅ FRAME01 — Controller & Routing
  • ✅ FRAME02 — Stateful Pages & Components
  • ✅ FRAME03 — Actions
  • ✅ FRAME04 — Optimized Bundling
  • ✅ TECH01 — Use PlainJS & Custom Framework
  • ✅ TECH02 — Use SAAS for CSS
  • ✅ TECH03 — Use WebSockets to Connect Frontend and Backend

Conclusion

Footnotes

  1. At the time of writing, websocket.io v 3.0 was released, but I could not get it working and choose the older v2.3 instead.
  2. In this example, the express configuration is rather plain, but you can add any other express module, e.g. for handling static files or for setting CORS values.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store