Struggling to pass express.js router requests and responses to a class method

I am struggling with setting up an Express JS router.

I am facing difficulty passing req and res to my class method.

Not Working app.get('/', controller.index)

Working

app.get('/', (res,req) => controller.index(req,res)

The routing flow I implemented follows this path:
app.js (Main file) > /routes/index.js > /routes/user.route.js > /controllers/user.controller.js > /services/user.services.js

app.js

import express from 'express';
import cors from 'cors';
import routes from './routes';
import db from './models';
import dotenv from 'dotenv';

dotenv.config();
const app = express();
const port = process.env.PORT || 3001;

app.use(cors())
app.use(express.json());
app.use(express.urlencoded({ extended: false }));

// Database Initialize
db.sequelize.sync()
.then(() => {
    console.log("🚀 Database Connected.");
}).catch((err) => {
    console.log("❌ Failed Connect to Database");
})

// Router
app.use(routes);

//global dir
global.__basedir = __dirname;

app.enable("trust proxy");

app.listen(port, () => {
  // logger.info("Checking the API status: Everything is OK");
  console.log(`🚀 App listening on port ${port}`);
})

routes/index.js

import express from "express";
import appRoutes from './app.routes';
import roleRoutes from './role.routes';
import userRoutes from './user.routes';
import authRoutes from './auth.routes';

const app = express();

// App Routes
app.use('/app', appRoutes);
// Role Routes
app.use('/role', roleRoutes);
// User Routes
app.use('/user', userRoutes);
// Auth Routes
app.use('/auth', authRoutes);

export default app;

routes/user.routes.js

import express from 'express';
import userController from '../controllers/user.controller';
import validateAuth from '../middlewares/validateAuth';

const app = express();
const controller = new userController;

app.get('/', controller.index);

export default app;

controllers/user.controller.js

import userServices from "../services/user.services";
import baseController from "./base.controller";

export default class userController extends baseController {
    constructor() {
        super(new userServices());
    }
}

controllers/base.controller.js

import response from "../helpers/response";
import lang from "../helpers/lang";
import dotenv from "dotenv";
dotenv.config();

export default class baseController {
    constructor(service) {
        this.service = service
    }

    /**
     * Index
     * Get all data with pagination
     */
    async index(res, req) {
        try {
            const data = await this.service.paginate(req.query);
            if(data) {
                return response.success({
                    res,
                    message: lang[process.env.LANG].DATA_LOADED,
                    data
                });
            } else {
                throw new Error(lang[process.env.LANG].REQUEST_FAILED);
            }
        } catch(err) {
            console.log(err)
            return response.error({
                res,
                message: err.message,
            });
        }
    }
}

services/user.services.js

import baseServices from "./base.services";
import db from "../models";

export default class userServices extends baseServices {
    constructor() {
        const attributes = [
            "roleId",
            "appId",
            "username",
            "password",
            "name",
            "phone",
            "email",
            "isActive",
        ];
        super(db.user, attributes);
    }

    /**
     * Paginate
     * @param {{
     *  search: string,
     *  limit: number,
     *  offset: number,
     *  sortBy: string,
     *  orderBy: string,
     *  user: object
     * }} data
     * return Promise
     */
    paginate(data) {
        const { search, limit, page, sortBy, orderBy, user } = data;

        const offset = limit
            ? parseInt(limit) * parseInt(page) - parseInt(limit)
            : 0;

        let filter = {};
        if (search)
            Object.assign(filter, { name: { [Op.like]: `%${search}%` } });

        const condition = {
            where: filter ? filter : "",
            order: sortBy ? [[sortBy, orderBy]] : [["name", "asc"]],
            limit: limit ? parseInt(limit) : 10,
            offset,
            include: ["role", "app"]
        };

        return this.model.findAndCountAll(condition);
    }
}

services/base.services.js

import db from "../models";
const Op = db.Sequelize.Op;

/**
 * Base Services Class
 */
export default class baseServices {
    constructor(model, attributes = []) {
        this.model = model;
        this.attributes = attributes
    }
}

Response

Not Working app.get('/', controller.index)
Error Response

Working

app.get('/', (res,req) => controller.index(req,res)

Success Response

I attempted changing const app = express() and const app = express.Router() but the issue persists.

Answer №1

I've noticed a couple of issues in your code:

  1. One problem is that you're losing the controller object in the index method due to how you are passing it.

  2. There seems to be confusion with the order of the (req, res) arguments as well.

The controller.index() method defines them in reverse order:

async index(res, req) { ... }

This causes an issue when you call:

app.get('/', controller.index)

since Express passes the arguments as

(req, res)</code while your method expects them as <code>(res, req)
.

That's why this alternative works:

app.get('/', (res,req) => controller.index(req,res));

because it reverses the arguments again.


To fix this, update the method like this:

async index(req, res) { ... }

to align with how Express delivers the arguments and ensure they match up correctly.

Moreover, since your controller object has instance data and the index method uses this, you should also make sure the index method receives its instance properly by modifying to:

app.get('/', controller.index.bind(controller));

Answer №2

You must adhere to the proper MVC design pattern and echo after me, your app.js file should look like this:

require ('dotenv').config();
const routes =  require('./routes');
const express = require('express');
const app = express();
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
const cors = require('cors');
const db = require('./models');

const port = process.env.PORT || 3001;

app.use(cors());
app.use(express.json());

// Database Initialization
db.sequelize.sync()
.then(() => {
    console.log("🚀 Database Connected.");
}).catch((err) => {
    console.log("❌ Failed Connect to Database");
})

// Routing
app.use(routes);

//global dir
global.__basedir = __dirname;

app.enable("trust proxy");

app.listen(port, () => {
  // logger.info("Checking the API status: Everything is OK");
  console.log(`🚀 App listening on port ${port}`);
})

The structure of routes/index.js should be as follows:

const router = require("express").Router();

router.use('/app', require(./app.routes"));
router.use('/role', require("./role.routes"));
router.use('/user', require("./user.routes"));
router.use('/auth', require("./auth.routes"));


module.exports = router;

All your routes files should follow a similar format

user.routes

const userController = require("whatever the location");
const router = require("express").Router();

router.post("/example", userController.controller);

module.exports = router;

The userController file:

const userServices = require("what ever the location");

const controller = async (request, response) => {
    try {
        //code goes here
        await userServices.addUser(
        {
                "name": "ALI",
                "gender": "MALE",
        }
    )
    } catch (error) {
        console.log(error);
        response.status(500).json({
            error: "Something went wrong",
        });
    }
}

module.exports = {
    controller
}

Lastly, the userServices file is:

const user = require("what ever the location");

const addUser = async (data) => {

    return new Promise((resolve, reject) => {
        new user(data)
            .save()
            .then((data) => resolve(data))
            .catch((err) => reject(err));
    });

}

module.exports = {
    addUser
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Latest output is fetched by jQuery from the load() method

I'm encountering an issue with the code present in index.html: $(document).ready(function() { $('#generate').click(function() { //$("#results").empty(); $("#results").html(""); $("#results").load("generate.php"); }); }); In addition ...

Using regular expressions, you can locate and replace the second-to-last instance of a dot character in an email address

I'm looking to replace the second last occurrence of a character in a given string. The length of the strings may vary but the delimiter is always the same. Here are some examples along with my attempted solutions: Input 1: james.sam.uri.stackoverflo ...

Tips on preventing the occurrence of double encoding in raw JSON output from a view

I am encountering a JavaScript error while attempting to parse JSON data obtained from my controller: Uncaught SyntaxError: Unexpected token & in JSON at position 1 at JSON.parse () at stores:76 This is the code I use to serialize my list of elem ...

Error: The function $(...).draggable is not recognized" and "Error: The object $.browser is not defined

I encountered an error stating, TypeError: $(...).draggable is not a function. To resolve this issue, I added jQuery as follows: <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script> < ...

Access the CSV file using Office365 Excel via a scripting tool

Objective I want to open a CSV file using Office365's Excel without actually saving the file on the client's machine. Challenge The issue with saving raw data on the client's machine is that it leads to clutter with old Excel files accumu ...

The store for WrappedApp was just initialized using withRedux(MyApp) { initialState: undefined, initialStateFromGSPorGSSR: undefined }

I am trying to create multiple routes with express and next.js. After running npm run export, I encountered the following message: next export info - using build directory: C:_PROJECT.next info - Copying "static build" directory info - Launching 3 wor ...

"Utilizing AngulaJS to apply a class to the parent element when a radio button is

I'm wondering how I can assign a class to the parent div of each radio button in a group? You can find the code below and view the corresponding JSFiddle here. Here is the HTML: <div class="bd"> <input type="radio" ng-model="value" val ...

Implementing setTimeout with the copy button: A guide

How can I implement a setTimeout function in the copy button so that when a user clicks on it, the text will change to "copied" and then revert back to "copy" after 3-4 seconds? Please help me find a solution to this problem and also optimize the JavaScrip ...

An unexpected error has occurred in the browser console: The character '@' is not valid

I recently made the decision to dive into learning about Unit Testing with JavaScript. To aid in this process, I started using both Mocha.js and Chai.js frameworks. I downloaded the latest versions of these frameworks onto my index.html from cdnjs.com. How ...

Caution: A NaN value was received for the `value` attribute. To address this issue, consider converting the value to a string when dealing with input on a multipart

I have successfully implemented a multipart form in React, and it appears that the text and file fields are passing data correctly to my console. However, I am encountering errors with the integer values. I understand that using parseInt is necessary to pa ...

Looking to cycle through arrays containing objects using Vue

Within my array list, each group contains different objects. My goal is to iterate through each group and verify if any object in a list meets a specific condition. Although I attempted to achieve this, my current code falls short of iterating through eve ...

Obtaining a response in string format using the $.ajax function

var module = (function(){ return{ loadData: function(url, success, error){ $.when($.ajax({ type: 'GET', cache: false, url: url, contentType: 'application ...

Capture data from clipboard as it is being pasted into Handsontable

Issue Description and Troubleshooting: In a nutshell, I am seeking a method to manage data copied from the clipboard to a handsontable. I came across a suggestion on how to fetch this information using jQuery in a stackoverflow post: $("#haras_excel_li ...

Remove array element by key (not numerical index but string key)

Here is a JavaScript array that I am working with: [#ad: Array[0]] #ad: Array[0] #image_upload: Array[0] 13b7afb8b11644e17569bd2efb571b10: "This is an error" 69553926a7783c27f7c18eff55cbd429: "Yet another error" ...

Using Vue.js's computed property to dynamically bind a class in v-bind

I am familiar with using v-bind:class when returning true or false from a computed function. I am curious to know if it is possible to use a computed property that matches the ID and value of a button being clicked. For example, clicking button 1 would al ...

How can I implement a jQuery popup that prompts users to log in or register if they are not currently authenticated?

My JavaScript code includes jQuery and AJAX functionality for a specific action. Whenever a user id is not provided, and there isn't one stored in the session, I aim to prompt the user with a dialog box asking them to either register or log in. Could ...

Implementing React and Material UI: Maximizing Vertical Space Usage for a Box Component

Currently, I am working on a web application using React combined with Material UI. Within my code snippet below, you will see three Box components in play. Box 1 and Box 3 have specific heights set, but I am looking for a way to make Box 2 occupy the re ...

Transform a span into a div while retaining its content and styles, ensuring compatibility with Internet Explorer

Is there a reliable JavaScript method to convert a span into a div while preserving its contents and the original classes of the span? The classes are pre-set, so hardcoding should be possible. <span class="my class"> <p class="conten ...

`The value of an element within an array changes automatically`

In my current setup, I have a traditional array where each element represents an HTML element. The issue arises when I manipulate these elements within the array; any changes made to the HTML element also reflect in the array automatically. However, I pref ...

Navigate to the homepage section using a smooth jQuery animation

I am looking to implement a scrolling feature on the homepage section using jquery. The challenge is that I want the scrolling to work regardless of the page I am currently on. Here is the HTML code snippet: <ul> <li class="nav-item active"> ...