'How to return json from callback function within the Lambda?
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
})
}
})
};
Solution 1:[1]
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.
Solution 2:[2]
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.
Solution 3:[3]
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.
Solution 4:[4]
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)
};
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Swaraj Giri |
Solution 3 | Praveen Kumar Palai |
Solution 4 | Mark |