简体   繁体   中英

Dynamically set property name of JavaScript object inside a function

I'm learning to build APIs with Express. I figured that every time I have to send a successful JSON response, I have to duplicate most of the code. So I tried to put it in a function like so in one of my controller modules:

const successResponse = (res, statusCode, obj, coll = false) => {
  const successObj = { status: "success" };
  if (coll) successObj.results = obj.length;
  successObj.data = { obj };
  return res.status(statusCode).json(successObj);
};

exports.getPlayer = asyncErrorHandler(async (req, res, next) => {
  const player = await Player.findById(req.params.id);
  if (!player) return next(new AppError("Player not found", 404));

  successResponse(res, 200, player);
}

The problem is in the line successObj.data = { obj } where I want the result to be the name of the argument that is passed as key and the object as value(s). The result I currently get is:

{
    "status": "success",
    "data": {
        "obj": { // I want this key to be "player" here
            "name": "Sal"
        }
    }
}

As the comment says I would like the key to be the string that I passed as the object name. I can do it by passing another argument as a string but it will always be the same as the object name that I pass. Is there a better way to do this?

You are getting a single object and trying to use that as key and value. You can try something like this:

Suppose your obj is

var obj = { player: { 
            "name": "Sal"
        }}

then while pushing to data you can follow these steps:

var selectedKey = Object.keys(obj)[0]; // assuming you will have a single key, if you have multiple then select based on the index

var selectedKeyData = Object.values(obj)[0];

var data = {};
data[selectedKey] = selectedKeyData;

Now, your data will have desired result.

You pass the name to the successResponse like this:

exports.getPlayer = asyncErrorHandler(async (req, res, next) => {
  const player = await Player.findById(req.params.id);
  if (!player) return next(new AppError("Player not found", 404));

  successResponse(res, 200, {objName: "player" , value: player);
}

And then change your successResponse like this:

// Set a suitable default value for objName (e.g. "obj") if you don't want to send it every time
const successResponse = (res, statusCode, {objName = "obj", value}, coll = false) => {
  const successObj = { status: "success" };
  if (coll) successObj.results = obj.length;
  successObj.data = { [objName]: {value}}; // { player : { name : "Sal"} }
  return res.status(statusCode).json(successObj);
};

EDIT 1 => NOTE: You can't access the name of the variable that passed to a function unless the name string was explicitly passed. Because only the value that a variable held is passed along not the name. This why you have to pass it the name. The solution I gave would not need another argument to function but it will need another key/value inside the object passed.

**EDIT 2 => ** Even more cleaner solution

exports.getPlayer = asyncErrorHandler(async (req, res, next) => {
  const player = await Player.findById(req.params.id);
  if (!player) return next(new AppError("Player not found", 404));

  successResponse(res, 200, {player}); //Same as {"player" : player}
}

And then change your successResponse like this:

const successResponse = (res, statusCode, obj, coll = false) => {
  const successObj = { status: "success" };
  if (coll) successObj.results = obj.length;
  successObj.data = { ...obj };
  return res.status(statusCode).json(successObj);
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM