Search code examples
node.jsexpresses6-promisefeathersjs

How does Promises work in node/feathersjs?


I made function like this, that should check if module is forbidden for current user. If it is - return error, if not - then let him do rest of hooks/proceed to api route. This method is called in service hooks.

function isAppForbidden(hook) {
  return new Promise((resolve, reject) => {
    hook.app.services.settings.find({
      query: {
        $limit: 1,
        $sort: {
          createdAt: -1
        }
      },
      user: {
        roleId: hook.params.user.roleId
      }
    }).then(res => {
      if(res.data.length > 0) {
        let userHiddenApps = hook.params.user.hiddenApps || [];
        let globalHiddenApps = res.data[0].forbiddenApps || [];
        if (userHiddenApps.indexOf('qualitydocs') >= 0 || globalHiddenApps.indexOf('qualitydocs') >= 0) {
          reject(new errors.Forbidden()); //throws error for forbidden moduels
        }
        resolve();
      }
    })
  })
}

before: {
    all: [
      authenticate('jwt'),
      hook => includeBefore(hook),
      hook => isAppForbidden(hook)
    ],
    find: [],
    get: [],
    create: [(hook) => {
      hook.data.authorId = hook.params.user.id;
    }],
    update: [],
    patch: [],
    remove: []
  },

On my local machine everything works just fine. If module is forbiden I get Forbiden error, if not then I get data from route. But on my production machine it doesnt work that way, if module is NOT forbidden (no error) I fail to receive any response as if it ended up in some kind of loop on 'resolve()' part?? Is it possible? does this promise look fine to you?

I know its weird question but i have no clue where to start since it works perfectly fine locally and no errors on production (except it breaks whole app, no responses anymore, till you reload page).


Solution

  • The problem is that if res.data.length <= 0 your promise will never resolve. In general, when using Feathers functionality you never have to call new Promise yourself because everything returns promises already. You can make your life even easier by using async/await which will make the code easier to follow and avoid your problem altogether:

    async function isAppForbidden(hook) {
      const res = await hook.app.service('settings').find({
        query: {
          $limit: 1,
          $sort: {
            createdAt: -1
          }
        },
        user: {
          roleId: hook.params.user.roleId
        }
      });
    
      if(res.data.length > 0) {
        let userHiddenApps = hook.params.user.hiddenApps || [];
        let globalHiddenApps = res.data[0].forbiddenApps || [];
    
        if (userHiddenApps.indexOf('qualitydocs') >= 0 || globalHiddenApps.indexOf('qualitydocs') >= 0) {
          throw new errors.Forbidden(); //throws error for forbidden moduels
        }
      }
    
      return hook;
    }
    
    before: {
        all: [
          authenticate('jwt'),
          includeBefore,
          isAppForbidden
        ],
        find: [],
        get: [],
        create: [(hook) => {
          hook.data.authorId = hook.params.user.id;
        }],
        update: [],
        patch: [],
        remove: []
      },