8

Goal is to set the variable auth correctly for further use, hence i want to refactor the function loginUser:

function loginUser(user, request, auth) {
  return function(done) {
    request
      .post('/users/login')
      .send(credentials)
      .expect(200)
      .end(onResponse);

    function onResponse(err, res) {
      auth.token = res.body.token;
      return done();
    }
  };
}


 loginUser(user, request, auth)(function() {
  request.get(testUrl)
    .set('Authorization', `bearer ${auth.token}`)
    .expect(200, done);
});

to use async / await like this (without the callback):

auth = await loginUser(user, request);
request.get(testUrl)
    .set('Authorization', `bearer ${auth.token}`)
    .expect(200, done);

But i am struggling of returning / setting auth correctly (it would not matter if i pass auth as parameter or as return value).

What i tried was stuff like this:

async function loginUser(user, request) {
  let auth;
  await request
    .post('/users/login')
    .send(credentials)
    .expect(200)
    .end(onResponse);

  function onResponse(err, res) {
    auth.token = res.body.token;
  }
  return auth;
}

But auth was never set correctly.

Gobliins
  • 3,848
  • 16
  • 67
  • 122
  • Possible duplicate of [Promises es6 and superagent](https://stackoverflow.com/questions/27967000/promises-es6-and-superagent) – k0pernikus Jul 20 '18 at 09:12
  • hmm not sure, since i want to get rid of the callback when calling the login function – Gobliins Jul 20 '18 at 09:18

2 Answers2

11

Don't use 'end' syntax, that's for callbacks:

const response = await request.post(...)
  .expect(200)
const {body: {token}} = response
return token

Basically it should look like sync code

Lev Kuznetsov
  • 3,520
  • 5
  • 20
  • 33
  • You are right, but you could've added some details in the `(...)` i had some trouble understanding how to rewrite my code. – Gobliins Aug 01 '18 at 13:20
  • The part about `const {body: {token}} = response` was a bit confusing for me, ended up trying `const {response} = await...` which resulted in undefined response. Doing `let response = await...` worked fine. Just leaving this as note for anyone else who might get confused about this.. Superagent is nice, but the await syntax seems a bit lacking in examples. Anyway, it works now.. I guess your example is just addressing the specifc OP question on parsing the token from the body, and the syntax is a bit strange to me. – kg_sYy Dec 21 '20 at 11:04
3

The problem is that the onResponse method is being executed later than you the return of the function because of the event loop in Nodejs. So you will have to do resolve the promise exactly when you receive the data

The method loginUserInternal could be like this:

function loginUserInternal(user, request) {
  return new Promise((resolve,reject) => {
    let auth = {};
    request
      .post('/users/login')
      .send({
        username: user.username,
        password: user.password_decoded,
      })
      .expect(200)
      .end(onResponse);
    function onResponse(err, res) {
      if(err) return reject(err)
      auth.id = res.body.id;
      auth.token = res.body.token;
      auth.tokenExpires = res.body.tokenExpires;
      resolve(auth)
    }
  })
}

And call it like you were doing with async await.

David Viejo
  • 751
  • 1
  • 6
  • 6
  • Can you show how to call it? I always end up with a timeout of 2000ms, Unhandled promise rejection or Promise { }. Also onResponse needs a return value when no error occurs or skip return complete (i did it this way). – Gobliins Jul 20 '18 at 10:18
  • Like you had in your post `auth = await loginUser(user, request);`, if it gives you promise rejection is that the request has failed, try to do a `console.log(err)` to see what's going on – David Viejo Jul 20 '18 at 19:47