Create a Basic Framework with Express (Part 1)
Tags: express, node, tutorial
Published: 2023-03-20 16:15:00

We will be using Docker, Node 18, MySQL 8, and Redis. Following [Setting Up Node App using Docker](https://dev.to/devlogbook/setting-up-node-app-using-docker-3kd0) post express, nodemon, dotenv packages should be installed.

In this application, we will not be writing a rest app, it will be a basic full stack framework. Packages will be installed once we reach the point where we need to use them.

## Create Project Structure

```
node_modules
public
controllers
database
helpers
middlewares
routes
storage
views
```

## Setup Logging

1. Install [Winston](https://www.npmjs.com/package/winston)
    ```
npm install winston
    ```

2. To be able to write daily logs instead of a single log, install [Winston Daily Rotate File](https://www.npmjs.com/package/winston-daily-rotate-file)
    ```
npm install winston-daily-rotate-file
    ```

3. Create a **logger.js** helper in **helpers** directory
    - We want to have it log into daily log files of max size of 1GB and will be kept for 10 days.

    ```js
    const winston = require('winston')
    const { format } = winston
    const { combine, timestamp, printf, splat } = format
    require('winston-daily-rotate-file')

    const dailyTransport = new winston.transports.DailyRotateFile({
        // file name format
        filename: 'application-%DATE%.log',
        datePattern: 'YYYY-MM-DD',
        zippedArchive: true,
        // limit each log to 1GB
        maxSize: '1g',
        // format the log
        format: combine(
            timestamp(),
            splat(),
            printf((info) => {
                return `[${info.timestamp}] ${info.level}: ${info.message}`
            })
        ),
        level: 'info',
        // save logs into storage/logs
        dirname: 'storage/logs',
        // save logs for 10 days
        maxFiles: '10d',
    })

    const logger = winston.createLogger({
        transports: [dailyTransport],
    })

    module.exports = logger
    ```

4. Create a **errorHandler.middleware.js** helper in **middlewares** directory
    -  Log the error and send a response to the user
    ```js
    // import logger helpers
    const loggerx = require('../helpers/logger')

    const errorHandler = {
        // log the error
        logger: (error, request, response, next) => {
            loggerx.error(`${error.message} %o`, error)
            next(error) // calling next middleware
        },

        responder: (error, request, response, next) => {
            const status = error.statusCode || 500
            // send status and error message
            return response.status(status).send(error.message)
        }
    }
    module.exports = errorHandler;
    ```

5. Add the error handler middleware to **index.js** and test it out!
    ```js
    ...
    const express = require('express')
    const app = express()
    
    // import the logger helper so we can test the logging
    const logger = require('../helpers/logger')
    // import the error handler
    const errorHandler = require('./middlewares/errorHandler.middleware.js')
    
    ...
    
    // Cause an error
    app.get('/error', async (req, res, next) => {
        try {
            let error = new Error('This is a major issue!!')
            error.statusCode = 500
            throw error
        } catch (error) {
            return next(error)
        }
    })
    
    // Just logging
    app.get('/log', async (req, res, next) => {
        logger.info('hello from /log')
        res.send('hello')
    })

    // log the error
    app.use(errorHandler.logger)
    // send error to user
    app.use(errorHandler.responder)
    
    ...
    
    ```
    - Go to `localhost:3000/error` and `localhost:3000/log`, the log file can be found in **storage/logs** (example below)
    ```log
    [2023-03-20T00:41:29.652Z] error: This is a major issue!! Error: This is a major issue!!
        at /app/index.js:28:25
        at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
        at next (/app/node_modules/express/lib/router/route.js:144:13)
        at Route.dispatch (/app/node_modules/express/lib/router/route.js:114:3)
        at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)
        at /app/node_modules/express/lib/router/index.js:284:15
        at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12)
        at next (/app/node_modules/express/lib/router/index.js:280:10)
        at expressInit (/app/node_modules/express/lib/middleware/init.js:40:5)
        at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5) {
    [stack]: 'Error: This is a major issue!!\n' +
        '    at /app/index.js:28:25\n' +
        '    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)\n' +
        '    at next (/app/node_modules/express/lib/router/route.js:144:13)\n' +
        '    at Route.dispatch (/app/node_modules/express/lib/router/route.js:114:3)\n' +
        '    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)\n' +
        '    at /app/node_modules/express/lib/router/index.js:284:15\n' +
        '    at Function.process_params (/app/node_modules/express/lib/router/index.js:346:12)\n' +
        '    at next (/app/node_modules/express/lib/router/index.js:280:10)\n' +
        '    at expressInit (/app/node_modules/express/lib/middleware/init.js:40:5)\n' +
        '    at Layer.handle [as handle_request] (/app/node_modules/express/lib/router/layer.js:95:5)',
    [message]: 'This is a major issue!!',
    statusCode: 500
    }
    [2023-03-20T00:41:59.271Z] info: hello from /log
    ```