Home > Blockchain >  Why does callback function work when there are fewer arguments?
Why does callback function work when there are fewer arguments?

Time:08-05

Code

Can someone please explain why this code works when in the function verifyUser, the function verifyToken is passed a callback function as the fourth argument. But if we look at the verifyToken function, it only has 3 parameters/arguments. How does this work????

import jwt from "jsonwebtoken";
import { createError } from "../utils/error.js";

export const verifyToken = (req, res, next) => {
  const token = req.cookies.access_token;
  if (!token) {
    return next(createError(401, "You are not authenticated!"));
  }
  //Verifying if token is correct
  //Error (err) or token data (user) are returned by verify function 
  jwt.verify(token, process.env.JWT, (err, user) => {
    if (err) return next(createError(403, "Token is not valid!"));
    req.user = user;
    next();
  });
};

export const verifyUser = (req, res, next) => {
  verifyToken(req, res, next, () => {
    if (req.user.id === req.params.id || req.user.isAdmin) {
      next();
    } else {
      return next(createError(403, "You are not authorized!"));
    }
  });
};

CodePudding user response:

I went digging in Express's source code and found this documentation

Once the next() function is invoked, just like middleware it will continue on to execute the route, or subsequent parameter functions.

Source

So it looks like next() first tries to call a callback argument if it it's passed, then tries to call the next middleware.

I think the reason they did this, is to hardcode or chain a call to verifyToken before verifyUser without changing their implementation of next() which would jump to the next middleware when called in verifyToken instead of continuing verifyUser.

I wrote an example script that uses the same idea here:

function printResult(object, next) {
  console.log("The final results is: "   object.result);
  next();
}

function printLog(object, next){
  console.log('Running printLog')
  console.log('The current result is: '   object.result)
  next();
}

function add5(object, next) {
  // Chain printLog before add5 so that it always runs before it
  printLog(object, next, () => {
    console.log('Now running add5')
    object.result = object.result   5;
    next();
  })
}


function addOne(object, next) {
  console.log('Running addOne')
  object.result = object.result   1;
  next();
}

function callStack(stack, object) {

  function next(index, object) {
    return function runNext() {
       let caller = runNext.caller
       if(caller.name !== '' && caller.arguments[2]) {
          caller.arguments[2]()
       } else if (stack[index   1]){
          stack[index   1](object, next(index   1, object));
       }
     }  
   }
   
  stack[0](object, next(0, object)); 
}

const stack = [addOne, add5, printResult]
const object = {result: 0}

callStack(stack, object)

Note that the anonymous function check caller.name !== '' is there because checking the arguments property of an anonymous function throws an error.

More thorough explanation of why this is important.

So if you're app is like this there's no problem:

  • Middleware 1
    • next() goes to next middleware
  • verifyToken (Middleware 2)
    • next() goes to next middleware
  • Middleware 3

But if it was like this and next() didn't call the parameter function:

  • Middleware 1
    • next() goes to next middleware
  • verifyUser (Middleware 2)
    • calls verifyToken
      • next() in verifyToken goes to next middleware <- This is an issue
    • Continue verifyUser <- Because this never happens
    • next() goes to next middleware
  • Middleware 3

So they let next() call a parameter function:

  • Middleware 1
    • next() goes to next middleware
  • verifyUser (Middleware 2)
    • calls verifyToken with verifyUser's implementation as a callback veryifyCB (jus an alias for th example)
      • next() in verifyToken checks for a callback, finds verifyCB and calls it
    • next() in verifyCB goes to next middleware
  • Middleware 3

CodePudding user response:

Fourth argument is in arguments object. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

  • Related