stackunderflow
stackunderflow

Reputation: 1714

Dynamically accessing function arguments

Hi have the following simple ExpressJS application, where the routes are dynamically created based on a configuration. I am having a hard time trying to pass in a bunch of parameters to the handler so that the values are returned in the respective controller.

const express = require('express');

module.exports = class App {
  get routes() {
    return [
      {
        path: '/',
        verb: 'get',
        method: 'home',
        params: ['req.query.ref', 'req.query.country'],
      },
    ];
  }

  constructor() {
    this.app = express();
    this.register();
  }

  register() {
    const { routes } = this;
    routes.forEach((route) => {
      const {
        path, verb, method, params,
      } = route;
      // if you replace the params with [req.query.ref, req.query.country] it will work as expected
      this.app[verb](path, this.handler(this[method].bind(this), (req, res, next) => params));
    });
  }

  handler(promise, params) {
    return async (req, res, next) => {
      const bound = params ? params(req, res, next) : [];

      console.log(bound);

      try {
        const result = await promise(...bound);
        res.json(result);
      } catch (err) {
        throw err;
      }
    };
  }

  home(payload) {
    console.log(payload);
    return Promise.resolve({ status: 'OK' });
  }
};

Upvotes: 3

Views: 184

Answers (3)

David Vicente
David Vicente

Reputation: 3111

Maybe you can take a look to the arguments object. All functions have this object and it contains an array with all arguments received in the function. I think it could be what you are looking for.

JavaScript functions have a built-in object called the arguments object.

The argument object contains an array of the arguments used when the function was called (invoked).

This way you can simply use a function to find (for instance) the highest value in a list of numbers:

This is an example how it works:

x = findMax(1, 123, 500, 115, 44, 88);

function findMax() {
    var i;
    var max = -Infinity;
    for (i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}

More info: https://www.w3schools.com/js/js_function_parameters.asp

Upvotes: 1

Amit Wagner
Amit Wagner

Reputation: 3264

well you can build the query if with split if your params has the same format

--update--

this solution is based on req or res with x params for each

const express = require('express');

module.exports = class App {
  get routes() {
    return [
      {
        path: '/',
        verb: 'get',
        method: 'home',
        params: ['req.query.ref', 'req.query.country'], //changed
      },
    ];
  }

  constructor() {
    this.app = express();
    this.register();
  }

  register() {
    const { routes } = this;
    routes.forEach((route) => {
      let {
        path, verb, method, params,
      } = route;
      
      this.app[verb](path, this.handler(this[method].bind(this), (req, res, next) => this. paramsStringToArrayValues(req, res,params))
      }));
    });
  }
  
  paramsStringToArrayValues(req, res,params){
      return  params.map(param => {
                  let paramArr = param.split('.');
                  let obj  = paramArr.shift() === 'req'? req : res
                  paramArr.forEach(key =>{
                    obj = obj[key]
                  })
                  return obj
      })
  }

  handler(promise, params) {
    return async (req, res, next) => {
      const bound = params ? params(req, res, next) : [];

      console.log(bound);

      try {
        const result = await promise(...bound);
        res.json(result);
      } catch (err) {
        throw err;
      }
    };
  }

  home(payload) {
    console.log(payload);
    return Promise.resolve({ status: 'OK' });
  }
};

Upvotes: 0

Etheryte
Etheryte

Reputation: 25319

Most of your issues stem from the structure of your route definition. It would make more sense to create direct references to the things you want to use, not noting function references etc down as strings.

get routes() {
    return [{
        path: '/',
        method: this.get,
        endpoint: this.home,
        paramMap: req => [req.query.ref, req.query.country],
    }];
}

Once you make the appropriate changes elsewhere, you no longer have the original problem you described.

Upvotes: 1

Related Questions