Node Express and WebSockets (WS) Boiler Plate
Tags: node, websockets, express, boilerplate
Published: 2020-05-22 15:43:19

In this post I will be sharing with you some of the practices I follow, and how I create my API's using Node, Express, and WebSockets. I have recently publicly published the boiler plate that I use at [https://github.com/itsUnsmart/express-ws-boiler](https://github.com/itsUnsmart/express-ws-boiler) so I decided to go over it.

#Project Structure
The main thing I think about when setting up my projects is readability. If I cannot read through the project structure easily to find what I need it can be a pain.

In order to make things easy I split everything into its own directory. The Express API goes into the `web` directory. The WebSocket goes into the `sockets` directory. Finally any helpers I made need go into the `helpers` directory. In this example I have only one `index.js` file in the helpers, however, in bigger projects I recommend making multiple files with a more specific name to the type of helper functions if needed.

Simplified:
```js
structure: {
  "/helpers": "Any helpers needed.",
  "/sockets": "Anything related to the websocket server.",
  "/web":     "Anything related to the express web server."
}
```

###Express Specifics
Specific to Express I have one main `index.js` file which starts the server, and sets up all the routing, as well as any other configuration needed. In order to make the routes in a clean structure I create a `routes` folder which contains an `index.js` that will parse out the routes into a single object for the main server file.
Example:
```js
module.exports = {
  example: require('./example')
}
```
In the above example it takes a route file called `example.js` and maps it to the "/example" path. The way the mapping works in the main `index.js` file is it require the route index file, and runs over the object keys.
```js
const routes = require('./routes')
Object.keys(routes).forEach(key => {
  app.use(`/${key}`, routes[key])
})
```

This means now any request which has `example` in the path will get routed to the code in the `example.js` file.
Meaning our simple hello world file:
```js
const { Router } = require('express')
const router = Router()

router.get('/', (req, res) => {
  return res.status(200).json({
    hello: 'world'
  })
})

module.exports = router
```
Will run when we go to `http://localhost:3000/example` and display:
`{"hello": "world"}`.

###WebSocket Specifics
Specific to WS I have one main `index.js` file which starts the server, and sets up all the methods, as well as any other configuration needed. In order to make the methods in a clean structure I create a `methods` folder which contains an `index.js` that will parse out the methods into a single object for the main server file. This file is identical to the Express equivalent in the routes folder.
```js
module.exports = {
  example: require('./example')
}
```
 
The difference is now in order to call the method I look for the method to call in the WebSocket message inside of the `method` parameter (Note that I code all WebSocket message to be JSON).
Example:
```js
const Methods = require('./methods')

// inside ws.on("message")
if (typeof data.method === 'string' && Methods[data.method]) {
  Methods[data.method](WSS, ws, data)
}
```
Now if we were to connect to the socket and send the following message:
`{"method": "example"}` it would run our `example` method and return a response containing `{"hello": "world"}`.

##Full structure
After this out full project structure would look like so:
```js
structure: {
  "helpers": {
    "index.js": "The main file combining all other helper files if any."
  },
  "sockets": {
    "index.js": "The main server and configuration file.",
    "methods": {
      "index.js": "The main methods file which combines all methods."
    }
  },
  "web": "Same as sockets replacing methods with routes."
}
```

##Errors
After working on projects that integrate with 3rd party services I truly understand how useful good error messages can be. I always make sure to give as much detail into why an error happened so anyone using it can understand what went wrong.

I do this by giving my errors an easy to read error message, a machine readable error code useful for doing switch statements on. As well as context into the error(s) that occured.

Example of a 404 error:
```js
{
  type: "error",
  message: "Not Found",
  code: "not_found",
  context_info: {
    errors: [
      {
        reason: "invalid_path",
        message: "The requested path could not be found",
        data: "/invalid/path",
        location: "path"
      }
    ]
  }
}
```
This error may be a bit overkill for a simple 404 error, however, it gives a user or even yourself a good insight into exactly what went wrong in the request. This is very useful, and makes debugging super easy.

##Easy Install
Would you like to use this boiler plate in your projects? The easiest way to install it into your projects is by using [`degit`](https://www.npmjs.com/package/degit). 
Run the command `degit itsUnsmart/express-ws-boiler`, and it will clone the repository into your current directory.

##Conclusion
That is the basics for how I structure my Node, Express, and WebSocket applications, and how I handle things such as errors. I am curious how do you structure your projects, and what do you like or dislike about how I structure mine?