I'm experimenting with Node.js in AWS Lambda. And, I've run into a problem with the code below. Result value and error value are always returned blank. I'm pretty sure this is just a scope issue I'm to tired to see. How do I capture the return value and pass it back in the response? I'm sure the programs is connecting to redis because I get an error message if I change the port or URL and I don't when they're set properly.
The return code:
{
"statusCode": 200,
"body": "{\"key\":\"q1\"}"
}
The program code:
const Redis = require("ioredis");
const redis = new Redis(6379, 'fredflenstone.lhpxwy.az.0002.use2.cache.amazonaws.com');
exports.handler = async(event)=>{
let key=event.key;
let response;
let resultValue;
let errorValue;
redis.get(key, (err, result) => {
if (err) {
errorValue=err;
} else {
resultValue=result;
}
});
response={
key: key,
resultValue: resultValue,
errorValue: errorValue
};
return {
statusCode: 200,
body: JSON.stringify(response)
};
};
The problem is due to promises. Your handler execution is completing before redis is returning the result. Following snippet should work:
const Redis = require("ioredis");
const redis = new Redis(6379, 'fredflenstone.lhpxwy.az.0002.use2.cache.amazonaws.com');
exports.handler = async(event)=>{
let key=event.key;
let response;
let resultValue;
let errorValue;
try{
resultValue = await redis.get(key);
}catch(error) {
errorValue = error;
}
response={
key: key,
resultValue: resultValue,
errorValue: errorValue
};
return {
statusCode: 200,
body: JSON.stringify(response)
};
};
It is because your call to "redis.get" is not resolved when "response" is sent.
You need to wait for the response :
await new Promise((resolve) => {
redis.get(key, (err, result) => {
if (err) {
errorValue=err;
} else {
resultValue=result;
}
resolve();
});
})
or even better turn the redis response into a promise response :
await new Promise((resolve, reject) => {
redis.get(key, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
})
})
.then((result) => resultValue = result)
.catch((err) => errorValue = err)
Related
here's I've my axios function wrapped within a custom function:
async function getOrder(orderId) {
// ...
await axios({
method: 'post',
url: endpoint + "/mymethod",
data: request
}).then(function (response) {
var data = response.data.result;
return data;
}).catch(function (error) {
return { "error": error };
});
}
but if than i call that function:
router.get('/getOrder/:id', (req, res) => {
let result = getOrder(req.params.id);
res.json(result);
})
it returns nothing (since its async and don't wait the .then()).
what's the best way to wrap axios/async function and call from outside?
I think you're missing await in your codes:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
====================
[New Update]
for me in API function:
async getOrder(orderId) {
try {
const response = await axios.post(endpoint + "/mymethod")
return response.data
} catch (error) {
return { "error": error }
}
}
and get the result:
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
===========
[New Update2] here is my sample async/await function with axios
const axios = require("axios")
async function getOrder(orderId) {
try {
const response = await axios.get("http://google.com")
return response.data
} catch (error) {
return { "error": error }
}
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
====================
[New Update3] new Promise with axios:
const axios = require("axios")
async function getOrder(orderId) {
// try {
// const response = await axios.get("http://google.com")
// return response.data
// } catch (error) {
// return { "error": error }
// }
return await new Promise((resolve, reject) => {
axios({
method: 'get',
url: "http://google.com"
}).then(function (response) {
var data = response.data
resolve(data)
}).catch(function (error) {
reject({ "error": error })
});
})
}
async function main() {
let result = await getOrder();
console.log(result, "##")
}
main()
I think you are missing an await so you do not return a promise but wait for the result of getOrder to be passed in res.json :
router.get('/getOrder/:id', async (req, res) => {
let result = await getOrder(req.params.id);
res.json(result);
})
Noob in nodejs here and still trying to learn how nodejs works. Could you please let me know how can I pass the callback response from "getDatafromCosmosDB" function into a variable in the main function and print those values.
When I try to assign getDatafromCosmosDB to a variable "respdata" and try to print it, it is not working.
async function main(params, callback) {
const logger = Core.Logger('main2', { level: params.LOG_LEVEL || 'info' })
try {
logger.info('main action')
const respdata = getDatafromCosmosDB(function(response){
console.debug(response)
return response
});
console.debug(respdata)
} catch (e) {
console.debug(e)
}
}
exports.main = main
async function getDatafromCosmosDB(callback){
var query = new azure.TableQuery()
.top(5)
tableService.queryEntities('myCosmosTable', query, null, function (error, result, response) {
if (!error) {
console.log('success')
return callback(result.entries)
}
});
}
Try something like this,
import {
createTableService,
services,
ServiceResponse,
TableQuery
} from 'azure-storage';
getDatafromCosmosDB(): Promise<ServiceResponse> {
return new Promise(async (resolve, reject) => {
this.tableService.queryEntities(
this.tableName,
query,
null,
(error, _, response) => {
if (!error) {
resolve(response);
} else {
reject(error);
}
}
);
});
}
and invoke like,
this.getDatafromCosmosDB().then(data => {
console.log(data);
}
I am trying to write an async lambda function which is calling a function for sign up a user in cognito.
my problem is that in my lambda function, it is not waiting for the result and finish the execution. would you mind check what is my issue? I am new to rxjs. please help me.
mylambda function
exports.handler = async (event, context) => {
//poolData and params will fetch from event
let source = await signup(poolData, params);
console.log(source);
});
my signup function
function signup(poolData, body) {
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
const { username, password, attributes } = body;
const attributesList = [];
if (Array.isArray(attributes)) {
attributesList.push(
...attributes.map(item => new AmazonCognitoIdentity.CognitoUserAttribute(item))
);
}
let source = Observable.create(observer => {
let output = (err, res) => {
if (err)
{
observer.error(err);
}
else
{
const cognitoUser = res.user;
const data = {
username: cognitoUser.getUsername(),
};
observer.next(data);
}
observer.complete();
}
userPool.signUp(username, password, attributesList, null, output);
});
let respond;
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
source.subscribe(subscriber);
}
module.exports = signup;
This behavior is totally normal.
So first thing first, an observable is not a promise which means you are not able to await a response with the await keyword, also I don't see anything to be returned from the signup function, which will probably lead to undefined to be logged anyways.
So how to fix that, one way to fix this issue is to use toPromise() which will turn your observable into a promise which then can be awaited wherever needed.
The other way (which is the rxjs way) will be to return from the signup function the observable and inside your handler function to subscribe for the response.
let subscriber = {
next(value) {
console.log('Subscriber - next: ', value);
respond = {
'statusCode': 200,
'body': JSON.stringify({
"username": value.username,
})
}
}, error(err) {
console.log('Subscriber - err: ', err);
respond = err;
},
complete() {
console.log('Subscriber - complete');
return response;
}
};
exports.handler = (event, context) => {
//poolData and params will fetch from event
signup(poolData, params).subscribe(subscriber);
})
I'm trying to develop an API post, in middle execution I have validation such as check name already in use or not. I set error handler callback, it successfully send response 'Already registered', but when I checked to CLI, it show error
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
I dont know whats wrong, I use this error handler in the past and it seems look ok.
Here is my code in router:
createUserAccount: async function (req, res) {
const programData = req.body;
try {
await service.create(programData, function (code, err, result) {
if (err) {
if(code === 409){
res.status(HTTPSTATUS.CONFLICT).send(err.message);
} else {
res.status(HTTPSTATUS.BAD_REQUEST).send(err.message);
}
} else {
res.status(HTTPSTATUS.CREATED).json(result);
}
})
} catch (e) {
console.log(e)
res.status(HTTPSTATUS.BAD_REQUEST).json("Failed.");
}
Here is my function in my service:
const config = require('#configs/config.json')
const sequelize = require('sequelize');
const SEQUELIZE = new sequelize(config[env]);
module.exports = {
createAccount: async (name, password, callback) => {
try {
let check,
institution_id;
const checkName = await Profile.count(
{
where: {
name: name
}
}
);
//result checkName = 1
if(checkName > 0){
//then successfully execute this condition and
return callback(409, 'Already registered.', null);
//this show in console ----> POST /API/v1/user/profile 409 616.152 ms - 31
}
await Login.create({
username: email,
password: password
}).then(resLogin => {
const response = {
id: resLogin.id,
}
callback(201, null, response);
}).catch( error => {
callback(400, error, null);
})
} catch (e) {
callback(400, e, null);
}
},
create: async (payload, callback) => {
let loginID = null;
let {
profile,
address
} = payload;
let {
name,
email,
password
} = profile;
try {
await module.exports.createAccount(name, password, function (code, error, result) {
if(error){
const res = {message: error};
//what I need is the execution is end in here
return callback(code, res, null);
}
loginID = result.id;
});
//but the fact is it still execute this whole function if got callback error from createAccount()
let transaction = await SEQUELIZE.transaction();
await Address.create(address, {transaction})
.then( async resAddress => {
await transaction.commit();
return callback(201, null, resProfile);
}).catch(async e => {
return callback(400, e, null);
})
} catch (e) {
console.log(e);
callback(e, null);
}
};
I have tried on both Async Handlers and Non-Async Handlers ways,
to implement dynamodb putItem method. it returned an invalid response.
Its works for commented setTimeout function.
I tried by promisify the dynomodb putItem method in Non-Async Handler way as mentioned and official documentation https://docs.aws.amazon.com/lambda/latest/dg/nodejs-handler.html. But still no luck.
can some one point me out the issue on code?
const AWS = require('aws-sdk');
const dynamodb = new AWS.DynamoDB({
region: 'ap-south-1',
apiVersion: '2012-08-10'
});
exports.lambdaHandler = async function(event) {
const promise = new Promise(function(resolve, reject){
// setTimeout(function(){
// console.log("resolvedx")
// resolve({statusCode: 200, body: "resolvedx"})
// }, 200)
dynamodb.putItem({
TableName: 'CUSTOMER_LIST',
Item: {
'CUSTOMER_ID': { N: '012' },
'CUSTOMER_NAME': { S: 'zzzza' }
}
}
, function(err, data) {
if (err) {
console.log("err", err);
reject(JSON.stringify({statusCode:200, body:err}));
} else {
console.log("success", data);
resolve(JSON.stringify({statusCode:200, body:data}));
}
})
})
return promise
}
as Non-Async Handlers
exports.lambdaHandlerx = (event, context, callback) => {
const dbPromise = () => new Promise((resolve, reject) => {
console.log("inside db promise")
dynamodb.putItem({
TableName: 'CUSTOMER_LIST',
Item: {
'CUSTOMER_ID': { N: '023' },
'CUSTOMER_NAME': { S: 'asdddwa' }
}
}
, function(err, data) {
if (err) {
console.log("err", err);
reject(err);
} else {
console.log("success", data);
resolve(data);
}
})
})
Promise.all([dbPromise()]).then(data => {
console.log("then", data)
callback(null, {
'statusCode': 200,
'body': JSON.stringify({
message: "dataxz"+ JSON.stringify(data)
})
})
}
).catch(e => {
callback(null, {
'statusCode': 200,
'body': JSON.stringify({
message: 'err'
})
})
})
}
Output
Function returned an invalid response (must include one of: body, headers, multiValueHeaders or statusCode in the response object). Response received: