Creating Node Applications using SOLID principles
Tags: node, solid, express, javascript
Published: 2020-04-02 14:08:40

It's easy to create a Node application (using for example the Express framework). The following example is generated by `express-generator` and works perfectly:


```js
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
```

The problem with an application built this way is maintenance. Adding new features or fixing a bug may seem easy when we are in the project development phase. After several months without seeing the project, a simple addition of functionality can take several hours.

Design patterns were created to solve this problem: **Maintenance**! Don't think that a pattern will make you write less code, we always write more code or create more files. 

Among the hundreds of existing standards, we have one in particular called SOLID, which is a mnemonic acronym for five design principles intended to make software designs more understandable, flexible and maintainable.

Among these 5 principles, we will use the first two to write a Node application in a more organized way.

The first is called **Single Responsibility Principle** (the letter S) and has the following concept: **A class should have one, and only one, reason to change**. That is, a class or file should do only one thing, and have only one responsibility. A class/file that performs several distinct tasks should be avoided as much as possible.

The first example code displayed at the beginning of this article does not follow the SRP (Single Responsibility Principle) rule since the code performs several distinct functions. 

The second principle is called **Open Closed Principle** (the letter O) and has the following concept: **A class or file should be open for extension but closed for modification**. In other words, when writing a new feature in the application, the ideal is to create a new file or class instead of editing the existing code.

Using just these two rules, we will create a Node application using the Express framework, in a structured way.

## Project creation

With Node 8 or higher installed, run the following command on your favorite terminal.

```
$ mkdir solid-express-app
$ cd solid-express-app
$ npm init -y
```

The `npm init -y` command will create the `package.json` file with some initial settings:

![](https://i.imgur.com/IW10I0g.png)

Install the Express framework with the following command:

```
$ npm i -s express
+ express@4.17.1added 50 packages
found 0 vulnerabilities
```

The `npm i` (acronym for `npm install`) command installs a node package, and the `-s` attribute will record the package in the `package.json` file. The `package.json` file now has the following structure:

![](https://i.imgur.com/UTHUDj9.png)

Create the `index.js` file and use your favorite text editor to open the `solid-express-app` folder.  In this article we will use the Visual Studio Code. 

```
$ touch index.js
$ code .
```

![](https://i.imgur.com/PCVK9Dc.png)

Initially create the following code:

```js
const express = require('express')
const app = express();

app.get('/', function(req,res) {
    res.send('Hello Wolrd dev.to')
})

app.listen(3000, function () {
    console.log('Server running...')
})
```

To run this code, we will use the `nodemon` package which has the feature to restart the node service whenever the file changes.

```
$ npm i -D nodemon
```

We installed the `nodemon` with the `-D` option, which will save this package to the `devDependencies` of `package.json`. If you don't know this option or aren't familiar with Node, see more information at this [link](https://nodejs.dev/npm-dependencies-and-devdependencies).

Edit the `package.json` file and add the **start** script, according to the code below:

```json
{
  "name": "solid-express-app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "nodemon index.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.2"
  }
}
```

To run the start script, execute the following command:

![](https://i.imgur.com/Xh0DcGu.png)

With the server running, open in the browser the following address: http://localhost:3000

![](https://i.imgur.com/OwZcQc4.png)

## Reviewing the project

The application created so far has only the index.js file, and this contains two distinct features. The first uses the command `app.get` to create a route, answering with the message "Hello World dev.to". The second uses the `app.listen` command to start the web server.

To use the SOLID pattern, we have to isolate each functionality in files, and make the `index.js` file run these features. 

First, it is necessary to separate the functionalities of the application. If you have no experience with Node development, the important thing is to understand how it will be created. We will add each feature in a folder called "libs".

```js
const express = require('express')
const app = express()

const libs = require('./libs')
libs.forEach(lib => require(`./libs/${lib}`)(app))
```
The `require('./libs')` code will fetch from the file `./libs/index.js`, and on the next line we use the `forEach` command to run each file, passing the `app` constant.


Create the libs directory, and add the `index.js` file with the following code:

```js
module.exports = [
    'helloWorld',
    'start'
]
``` 

Add the file `libs/helloWorld.js`, with the following code:

```js
module.exports = app => {
    app.get('/', function(req,res) {
        res.send('Hello Wolrd dev.to')
    })
}
```

Add the file `libs/start.js`, with the following code:

```js
module.exports = app => {
    app.listen(3000, function () {
        console.log('Server running...')
    })
}
``` 

So far, we have the following files on the project:

![](https://i.imgur.com/fwwpM7h.png)

The result of this refactoring is the same for the user. In the browser, there is no change. Now, we are respecting the **Single-responsibility principle** because each functionality is properly separated into files, and the **Open-closed principle** because when creating a new functionality, we must create a new file.

## Adding new features

For example, if we want to add a new feature, like the `cors` module, we should do the following:

```
$ npm i -s cors
```

Change the `libs/index.js` file:

```js
module.exports = [
    'cors',
    'helloWorld',
    'start'
]
```

Add the `libs/cors.js` file:

```js
const cors = require('cors')

module.exports = app => {
    app.use(cors({
        exposedHeaders: 'Authorization'
    }))
}
```

When adding the **cors** module, see that we created a new http header in the request called `exposedHeaders'. To check if this change worked, use the __Google Chrome Dev Tools__ (F12 key) and on the network tab search for "Access-Control-Expose-Headers".

![](https://i.imgur.com/rYqia2I.png)

## Conclusion

The use of design patterns can slow down the pace at which you write software a little. Whenever you create a new feature you should create a new file, this can be boring or tedious at first, but it will help you maintain the software over time. 

For example, if from this moment on you assume that all software will follow the SOLID standard, you will know in the future that no matter what project you are carrying out maintenance, when creating a new feature you should create a new file or class. 

To access a more complex project, check this [github project](https://github.com/danielschmitz/express-solid)

If you found an error in my English, please let me know at danieljfa at gmail dot com