5

I'm trying to return the login status from the Cognito callback function, which is written in the NodeJS Lambda. However when I call the API the response keep loading and I'm getting warning error.

Here is my code:

'use strict';

global.fetch = require('node-fetch');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');

module.exports.hello = async (event, context) => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: "Hello there"
    }),
  };

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};


module.exports.register = async (event, context, callback) => {

  let poolData =  {
      UserPoolId : 'xxxxx', // Your user pool id here
      ClientId : 'xxxxxxx' // Your client id here
  } // the user Pool Data

  let userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);

  let attributeList = [];

  let dataEmail = {
      Name : 'email',
      Value : '[email protected]'
  };

  let dataName = {
      Name : 'name',
      Value : 'Jack'
  };

  var dataPhoneNumber = {
      Name : 'phone_number',
      Value : '+94234324324234' // your phone number here with +country code and no delimiters in front
  };

  let attributeEmail = new AmazonCognitoIdentity.CognitoUserAttribute(dataEmail);
  let attributeName = new AmazonCognitoIdentity.CognitoUserAttribute(dataName);
  var attributePhoneNumber = new AmazonCognitoIdentity.CognitoUserAttribute(dataPhoneNumber);

  attributeList.push(attributeEmail);
  attributeList.push(attributeName);
  attributeList.push(attributePhoneNumber);

  userPool.signUp('[email protected]', 'H1%23$4jsk', attributeList, null, function(err, result){

    let data = {};

    if (err) {
      callback(null, {
          statusCode: 500,
          body: JSON.stringify({
            status: 'FAIL',
            message: err.message
          }),
        });
      } else {
        let cognitoUser = result.user;

        callback(null, {
          statusCode: 200,
          body: JSON.stringify({
            status: 'SUCCESS',
            message: '',
            data: {
              username: cognitoUser.getUsername(),
              id: result.userSub
            }
          }),
        });
      }
  })

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};

The warning error as follows:

Serverless: Warning: handler 'register' returned a promise and also uses a callback!
This is problematic and might cause issues in your lambda.

Serverless: Warning: context.done called twice within handler 'register'!

serverless.yml

service: test-auth 
plugins:
  - serverless-offline

provider:
  name: aws
  runtime: nodejs8.10
  stage: dev
  region: us-east-1

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: message
          method: get
  register:
    handler: handler.register  
    events:
      - http:
          path: register
          method: post

Any help would be appreciated, Thanks in advance.

EDIT (2019-04-01):

module.exports.register = (event, context) => {

  ...

  userPool.signUp('[email protected]', 'H1%23$4jsk', attributeList, null, function(err, result){

    // for testing purpose directly returning 
    return {
      statusCode: 500,
      body: JSON.stringify({
        status: 'FAIL',
        message: err.message
      })
    }

  })

};

4 Answers 4

6

Its exactly what the error message states.

All async functions return promises. module.exports.register = async (event, context, callback) => {}

You are also using the callback by calling

callback(null, {
          statusCode: 500,
          body: JSON.stringify({
            status: 'FAIL',
            message: err.message
          }),
        });

Instead of using the callback, just return the either an error or a valid response.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the quick reply, after I removed the async I'm not getting any warning. However, it's also does not return anything if just return it. I'm now getting [Serverless-Offline] Your λ handler 'register' timed out after 30000ms. I even tried increasing the timeout value in the YML file but sill no use. Any what causing the error?
I'm still learning Node so please excuse my nube question. Isn't the first parameter in a callback supposed to be used for errors? In your example the first callback param is null and then the error.
5

Well the error is accurate. async wraps your return with promise. Either use callback all the way through like:

global.fetch = require('node-fetch');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');

// remove async
module.exports.register = (event, context, callback) => {

  ...

  // if you're using callback, don't use return (setup your callback to be able to handle this value as required) instead do:
  // calback({ message: 'Go Serverless v1.0! Your function executed successfully!', event })

  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};

Or don't use callback, use async/await (Promise) all the way through like:

module.exports.register = async (event, context) => {

  ...

  // needs promise wrapper, when using with promise, you might want to break up your code to be more modular
  const mySignUp = (email, password, attributes, someparam) => {
    return new Promise((resolve, reject) => {
      userPool.signUp(email, password, attributes, someparam, function(err, result) {

        let data = {};

        if (err) {
          reject({
            statusCode: 500,
            body: JSON.stringify({
              status: 'FAIL',
              message: err.message
            }),
          });
        } else {
          let cognitoUser = result.user;

          resolve({
            statusCode: 200,
            body: JSON.stringify({
              status: 'SUCCESS',
              message: '',
              data: {
                username: cognitoUser.getUsername(),
                id: result.userSub
              }
            }),
          });
        }
      })
    });
  }

  // call the wrapper and return
  return await mySignUp('[email protected]', 'H1%23$4jsk', attributeList, null);

  // don't use double return
  // Use this code if you don't use the http event with the LAMBDA-PROXY integration
  // return { message: 'Go Serverless v1.0! Your function executed successfully!', event };
};

Now register will return a promise. Elsewhere in your code you can call register like:

var result = register();
result
  .then(data => console.log(data))
  // catches the reject from Promise
  .catch(err => console.error(err))

or in async/await function (Note: `await` is valid only inside `async` function)

async function someFunc() {
  try {
    var result = await register();
    // do something with result
    console.log(result);
  } catch (err) {
  // reject from Promise
    console.error(err)
  }
}

Also note use strict is not required here as node modules use strict by default.

2 Comments

Thanks for the detail reply, however when I just return I'm getting timeout error [Serverless-Offline] Your λ handler 'register' timed out after 30000ms. I even tried increasing the timeout value in the YML file but sill no use (See my EDIT code ). when I tried the callback it just print the message in the command line. I just want to output the JSON response after the success of the callback function. The promise example you demonstrated working fine, however since it's blocking I don't want to use it. Any idea how can I solve this problem?
await is blocking as it pauses execution. If you don't want blocking then use the then callback for promise like somePromise.then(/*you can pass your callback function here*/() => //do something)
0

You are using an async function with a call back.

Try it this way:

Remove the callback from the async function.

async (event, context)

And modify the return as:

if (err) {
      return {
          statusCode: 500,
          body: JSON.stringify({
            status: 'FAIL',
            message: err.message
          })
        }
      }

And put an await on the function call.

1 Comment

Tried, still I'm getting the warning message and does not return anything.
0

If it helps anyone else catching this, you can add headers to the return:

return {
      statusCode: 200,
      headers: {"Content-Type": "application/json"},
      body: JSON.stringify(response.data)
    };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.