error firebase functions [Promises must be handled appropriately] on deploy - javascript
I was written a code previous week and it deploys without any error on firebase server. but now I cannot deploy it again on another account in orders to I don't change my code!
one of my friends tell me this in about new update of firebase but I don't find any solution for this!
it shows these errors
Promises must be handled appropriately
and
block is empty
the first error pointed to my first line and the second one pointed to end 'catch' block :
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp();
// export const helloWorld = functions.https.onRequest((request, response) => {
// console.log("sadegh");
// response.send("Hello from Firebase1!");
// });
//
export const sendChatNotification = functions
.firestore.document('rooms/{roomId}/messages/{messageId}')
.onCreate((snap, context) => {
const roomId = context.params.roomId;
const messageId = context.params.messageId;
const newValue = snap.data();
const receiverId = newValue.receiverId;
const text = newValue.text;
const type = newValue.type;
const senderName = newValue.senderName;
var p = admin.firestore().collection("users").doc(receiverId).get();
p.then(snapshot2 => {
const data2 = snapshot2.data();
const firebaseNotificationToken = data2.firebaseNotificationToken;
// const name = data2.name;
if (type == 'voiceCall' || type == 'videoCall' || type == 'hangUp') {
const channelId = newValue.channelId;
const senderId = newValue.senderId;
const status = newValue.status;
console.log("type: " + type + " /status: " + status)
let message = {
data: {
type: type,
senderId: senderId,
senderName: senderName,
receiverId: receiverId,
status: status,
channelId: channelId,
roomId: roomId
},
token: firebaseNotificationToken
};
sendMessage(message)
if (status == "canceled") {
let message1 = {
notification: {
title: '☎ Missed voice call ',
body: senderName
},
token: firebaseNotificationToken
};
sendMessage(message1)
} else if ((type == 'voiceCall' || type == 'videoCall') && status = '') {
let message1 = {
notification: {
title: '☎ ' + senderName + ' is calling you',
body: 'tap to answer...'
},
token: firebaseNotificationToken
};
sendMessage(message1)
}
} else {
let message = {
notification: {
title: '📃 ' + senderName,
body: text
},
token: firebaseNotificationToken
};
sendMessage(message)
}
return "";
}).catch((e) => {
console.log('error: ' + e);
return null;
});
// return "";
// }).catch(e=>{console.log('error: '+e)});
return "sadegh";
});
function sendMessage(message) {
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
}
Your code is a bit messy and it is not really easy to understand it without dedicating a long time.
However, here is below a piece of code that should work and that cover one case of your Business Logic. Note how the promises returned by the asynchronous tasks are returned.
export const sendChatNotification = functions.firestore
.document('rooms/{roomId}/messages/{messageId}')
.onCreate((snap, context) => {
const roomId = context.params.roomId;
const messageId = context.params.messageId;
const newValue = snap.data();
const receiverId = newValue.receiverId;
const text = newValue.text;
const type = newValue.type;
const senderName = newValue.senderName;
var p = admin
.firestore()
.collection('users')
.doc(receiverId)
.get();
return p.then(snapshot2 => { // <- HERE, the promise is returned
const data2 = snapshot2.data();
const firebaseNotificationToken = data2.firebaseNotificationToken;
if (type == 'voiceCall' || type == 'videoCall' || type == 'hangUp') {
const channelId = newValue.channelId;
const senderId = newValue.senderId;
const status = newValue.status;
console.log('type: ' + type + ' /status: ' + status);
let message = {
data: {
type: type,
senderId: senderId,
senderName: senderName,
receiverId: receiverId,
status: status,
channelId: channelId,
roomId: roomId
},
token: firebaseNotificationToken
};
return admin.messaging().send(message); // <- HERE, the promise is returned
}
});
});
I would suggest you watch the 3 videos about "JavaScript Promises" from the Firebase video series: https://firebase.google.com/docs/functions/video-series/
The problem is you commented the return in your catch block
As your Firebase .get() function must return a promise, in your code, if it fails, it won't return a promise and it will hang there.
either use return null or return something to be handled by the calling app
Related
nodejs TypeError: Cannot read property 'Message' of undefined
I have a lambda function in AWS. I use it to retrieve information from a REST API. When I test it runs returns a 200 status code, but an "ERROR TypeError: Cannot read property 'Message' of undefined at smsResponder (/var/task/smsResponder.js:33:35)" also shows. I have googled, and tried to use .responseText. My code is below. Should I be using return or something of the sort? 'use strict' const AWS = require('aws-sdk') AWS.config.update({ region: process.env.AWS_REGION || 'us-east-1' }) const { getStock } = require('./getStock') const KEYWORD = 'stock' const validateStock = function (elementValue){ let stockTest = AAPL return stockTest.test(elementValue) } const sendSMS = async function (params) { const pinpoint = new AWS.Pinpoint() console.log('sendSMS called: ', params) return new Promise((resolve, reject) => { pinpoint.sendMessages(params, function(err, data) { if(err) { console.error(err) reject(err) } else { console.log("Message sent. Data: ", data) resolve(data) } }) }) } const smsResponder = async (event) => { const msg = JSON.parse(event.Sns.Message) const msgWords = msg.messageBody.split(" ") // Check the first word of the text message is the keyword if (msgWords[0].toLowerCase() !== KEYWORD) return console.log('No keyword found - exiting') // Validate stock name and get price let message ='' const stockCode = msgWords[1] if (validateStock(stockCode)) { message = await getStock(stockCode) } else { message = 'Invalid stock symbol - text me in the format "stock stocksymbol".' } // Send the SMS response const params = { ApplicationId: process.env.ApplicationId, MessageRequest: { Addresses: { [msg.originationNumber]: { ChannelType: 'SMS' } }, MessageConfiguration: { SMSMessage: { Body: message, MessageType: 'PROMOTIONAL', OriginationNumber: msg.destinationNumber } } } } return console.log(await sendSMS(params)) } module.exports = { smsResponder }
The SNS-Event is differently structured, it should be event.Records[0].Sns.Message . Here are the docs: https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html
AWS-Lambda I get an error message " MissingRequiredParameter: Missing required key 'Data' in params" but have no 'Data' parameter called
I am trying to use AWS-Lambda to post data throught AWS-api gateway onto a client-side web-page but I am stuck on the above error message. When run the function run the database is displayed but then gets stuck on the error message. The three sets of code pasted bellow is what I'm using. If you can help let me know also if you need more info let me know database.js[ let AWS = require("aws-sdk"); //Create new DocumentClient let docClient = new AWS.DynamoDB.DocumentClient(); //Returns all of the connection IDs module.exports.getConnectionIds = async() => { let params = { TableName: "WebSocketClients" }; return docClient.scan(params).promise(); }; module.exports.getCNYData = async() => { let params = { TableName: "Currency", Limit: 100, ScanIndexForward: true, IndexName: "Currency_Name-Date-index", KeyConditionExpression: "Currency_Name = :Currency", ExpressionAttributeValues: { ":Currency": "CNY", } }; return docClient.query(params).promise(); }; module.exports.getGBXData = async() => { let params = { TableName: "Currency", Limit: 100, ScanIndexForward: false, IndexName: "Currency_Name-Date-index", KeyConditionExpression: "Currency_Name = :Currency", ExpressionAttributeValues: { ":Currency": "GBX", } }; return docClient.query(params).promise(); }; module.exports.getSARData = async() => { let params = { TableName: "Currency", Limit: 100, ScanIndexForward: false, IndexName: "Currency_Name-Date-index", KeyConditionExpression: "Currency_Name = :Currency", ExpressionAttributeValues: { ":Currency": "SAR", } }; return docClient.query(params).promise(); }; module.exports.getUSDData = async() => { let params = { TableName: "Currency", Limit: 100, ScanIndexForward: false, IndexName: "Currency_Name-Date-index", KeyConditionExpression: "Currency_Name = :Currency", ExpressionAttributeValues: { ":Currency": "USD", } }; return docClient.query(params).promise(); }; module.exports.getPositiveSentimentData = async() => { let params = { TableName: "Sentiment", Limit: 100, ScanIndexForward: false, IndexName: "Sentiment-Id-index", KeyConditionExpression: "Sentiment = :sentiment", ExpressionAttributeValues: { ":sentiment": "POSITIVE", } }; return docClient.query(params).promise(); }; module.exports.getNegativeSentimentData = async() => { let params = { TableName: "Sentiment", Limit: 100, ScanIndexForward: false, IndexName: "Sentiment-Id-index", KeyConditionExpression: "Sentiment = :sentiment", ExpressionAttributeValues: { ":sentiment": "NEGATIVE", } }; return docClient.query(params).promise(); }; module.exports.getData = async() => { let pSentiment = await module.exports.getPositiveSentimentData(); let nSentiment = await module.exports.getNegativeSentimentData(); let SAR = await module.exports.getSARData(); let CNY = await module.exports.getCNYData(); let USD = await module.exports.getUSDData(); let GBX = await module.exports.getGBXData(); let data = { positive: pSentiment, negative: nSentiment, CNY: CNY, GBX: GBX, SAR: SAR, USD: USD, }; return data; }; //Deletes the specified connection ID module.exports.deleteConnectionId = async(connectionId) => { console.log("Deleting connection Id: " + connectionId); let params = { TableName: "WebSocketClients", Key: { ConnectionId: connectionId } }; return docClient.delete(params).promise(); }; ] websocket.js[ let AWS = require("aws-sdk"); // Add ApiGatewayManagementApi to the AWS namespace require('aws-sdk/clients/apigatewaymanagementapi'); //Import functions for database let db = require('database'); module.exports.getSendMessagePromises = async(message, domainName, stage) => { //Get connection IDs of clients let clientIdArray = (await db.getConnectionIds()).Items; console.log("\nClient IDs:\n" + JSON.stringify(clientIdArray)); //Create API Gateway management class. const apigwManagementApi = new AWS.ApiGatewayManagementApi({ apiVersion: '2018-11-29', endpoint: domainName + '/' + stage }); //Try to send message to connected clients let msgPromiseArray = clientIdArray.map(async item => { try { console.log("Sending message '" + message + "' to: " + item.ConnectionId); //Create parameters for API Gateway let apiMsg = { ConnectionId: item.ConnectionId, Data: JSON.stringify(await db.getData) }; //Wait for API Gateway to execute and log result await apigwManagementApi.postToConnection(apiMsg).promise(); console.log("Message '" + message + "' sent to: " + item.ConnectionId); } catch (err) { console.log("Failed to send message to: " + item.ConnectionId); //Delete connection ID from database if (err.statusCode == 410) { try { await db.deleteConnectionId(item.ConnectionId); } catch (err) { console.log("ERROR deleting connectionId: " + JSON.stringify(err)); throw err; } } else { console.log("UNKNOWN ERROR: " + JSON.stringify(err)); throw err; } } }); return msgPromiseArray; }; ] index.js[ //Import external library with websocket functions let ws = require("websocket"); let db = require("database"); //Hard coded domain name and stage - use when pushing messages from server to client let domainName = "*********"; let stage = "dev"; exports.handler = async (event) => { try { //Get Message from event const msg = JSON.stringify(await db.getData(), function(key, value){ if (typeof value === "bigint") { return value.toString(); } else { return value; } }); //Allocate domain name and stage dynamically //domainName = event.requestContext.domainName; //stage = event.requestContext.stage; console.log("Domain: " + domainName + " stage: " + stage); //Get promises message to connected clients let sendMsgPromises = await ws.getSendMessagePromises(msg, domainName, stage); //Execute promises await Promise.all(sendMsgPromises); } catch(err){ return { statusCode: 500, body: "Error: " + (err)}; } //Success return { statusCode: 200, body: "Data sent successfully." }; }; ] Edit: For the two Dynamodb tables: Name:Currency Primary Partition Key: Date(String), Primary Sort Key: Currency_Name(String), Field: Price(BigInt), Index: Currency_Name-Date-index. Second table: Name: Sentiment Primary Partition Key: Id(Number), Primary Sort Key: Text(String), Field: Sentiment(string), Index: Sentiment-Id-index. Error Message: Response: { "statusCode": 500, "body": "Error: MissingRequiredParameter: Missing required key 'Data' in params" } Request ID: "e2fee9cd-4af1-489e-8aac-98e16139dd4d" Function Logs: 019-10-23"},{"Currency_Name":"USD","Price":"48.50","Date":"2019-10-22"},{"Currency_Name":"USD","Price":"47.32","Date":"2019-10-21"},{"Currency_Name":"USD","Price":"47.48","Date":"2019-10-18"},{"Currency_Name":"USD","Price":"48.69","Date":"2019-10-17"},{"Currency_Name":"USD","Price":"48.25","Date":"2019-10-16"},{"Currency_Name":"USD","Price":"47.00","Date":"2019-10-15"},{"Currency_Name":"USD","Price":"46.49","Date":"2019-10-14"},{"Currency_Name":"USD","Price":"46.10","Date":"2019-10-11"},{"Currency_Name":"USD","Price":"43.81","Date":"2019-10-10"},{"Currency_Name":"USD","Price":"43.65","Date":"2019-10-09"},{"Currency_Name":"USD","Price":"44.10","Date":"2019-10-08"},{"Currency_Name":"USD","Price":"45.66","Date":"2019-10-07"},{"Currency_Name":"USD","Price":"44.91","Date":"2019-10-04"},{"Currency_Name":"USD","Price":"42.70","Date":"2019-10-03"},{"Currency_Name":"USD","Price":"43.50","Date":"2019-10-02"},{"Currency_Name":"USD","Price":"45.50","Date":"2019-10-01"},{"Currency_Name":"USD","Price":"44.62","Date":"2019-09-30"},{"Currency_Name":"USD","Price":"45.67","Date":"2019-09-27"},{"Currency_Name":"USD","Price":"46.22","Date":"2019-09-26"},{"Currency_Name":"USD","Price":"44.42","Date":"2019-09-25"},{"Currency_Name":"USD","Price":"47.33","Date":"2019-09-24"},{"Currency_Name":"USD","Price":"45.83","Date":"2019-09-23"},{"Currency_Name":"USD","Price":"47.89","Date":"2019-09-20"},{"Currency_Name":"USD","Price":"48.23","Date":"2019-09-19"},{"Currency_Name":"USD","Price":"48.04","Date":"2019-09-18"},{"Currency_Name":"USD","Price":"47.77","Date":"2019-09-17"},{"Currency_Name":"USD","Price":"47.53","Date":"2019-09-16"},{"Currency_Name":"USD","Price":"49.21","Date":"2019-09-13"},{"Currency_Name":"USD","Price":"49.50","Date":"2019-09-12"},{"Currency_Name":"USD","Price":"47.74","Date":"2019-09-11"},{"Currency_Name":"USD","Price":"46.75","Date":"2019-09-10"},{"Currency_Name":"USD","Price":"47.19","Date":"2019-09-09"},{"Currency_Name":"USD","Price":"46.65","Date":"2019-09-06"},{"Currency_Name":"USD","Price":"45.39","Date":"2019-09-05"},{"Currency_Name":"USD","Price":"42.48","Date":"2019-09-04"},{"Currency_Name":"USD","Price":"41.79","Date":"2019-09-03"},{"Currency_Name":"USD","Price":"42.87","Date":"2019-08-30"},{"Currency_Name":"USD","Price":"41.63","Date":"2019-08-29"},{"Currency_Name":"USD","Price":"39.61","Date":"2019-08-28"},{"Currency_Name":"USD","Price":"40.72","Date":"2019-08-27"},{"Currency_Name":"USD","Price":"40.47","Date":"2019-08-26"},{"Currency_Name":"USD","Price":"42.07","Date":"2019-08-23"},{"Currency_Name":"USD","Price":"43.45","Date":"2019-08-22"},{"Currency_Name":"USD","Price":"43.25","Date":"2019-08-21"},{"Currency_Name":"USD","Price":"42.95","Date":"2019-08-20"},{"Currency_Name":"USD","Price":"43.53","Date":"2019-08-19"},{"Currency_Name":"USD","Price":"40.19","Date":"2019-08-16"},{"Currency_Name":"USD","Price":"39.77","Date":"2019-08-15"},{"Currency_Name":"USD","Price":"40.90","Date":"2019-08-14"},{"Currency_Name":"USD","Price":"39.55","Date":"2019-08-13"},{"Currency_Name":"USD","Price":"39.85","Date":"2019-08-12"},{"Currency_Name":"USD","Price":"41.25","Date":"2019-08-09"}],"Count":100,"ScannedCount":100,"LastEvaluatedKey":{"Currency_Name":"USD","Date":"2019-08-09"}}}' to: KYSQycomoAMCJdA= 2020-04-03T14:09:16.092Z e2fee9cd-4af1-489e-8aac-98e16139dd4d INFO Sending message '{"positive":{"Items":[{"Sentiment":"POSITIVE","Id":"1238393433607131100n","Text":"\"Nice, didn’t get boated 🤗 *********""}],"Count":1,"ScannedCount":1},"negative":{"Items":[{"Sentiment":"NEGATIVE","Id":"1238395098741825500n","Text":"\"RT #keira_churchill: GBP plummets against the Euro because coronavirus. GBP plummets against the USD because coronavirus. GBP plummets agai…\""},{"Sentiment":"NEGATIVE","Id":"1238392914813816800n","Text":"\"#keira_churchill GBP was already weakened by Brexit uncertainty/risks. Add CoronavEND RequestId: e2fee9cd-4af1-489e-8aac-98e16139dd4d
postToConnection requires Data attribute. In your case it will be undefined since JSON.stringify will return undefined when you try to stringify a function. This happens because you forgot the parenthesis when calling getData function. Replace: let apiMsg = { ConnectionId: item.ConnectionId, Data: JSON.stringify(await db.getData) // This results in undefined. }; With: let apiMsg = { ConnectionId: item.ConnectionId, Data: JSON.stringify(await db.getData()) // This works like you are expecting. };
Firebase cloud messaging Each then() should return a value or throw promise/always-return
I am writing a cloud function for firebase for my android app. I can't resolve this error. I am a complete newbie. 29:73 error Each then() should return a value or throw promise/always-return const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.sendNotification = functions.database.ref('/comment') .onWrite((change, context) => { // get user ids const reciever_id = context.params.reciever_id; const sender_id = context.params.sender_id; const comment = context.params.comment; const object_id = context.params.object_id; const objecttype = context.params.objecttype; //get the token of reciever return admin.database().ref("/users/" + reciever_id).once('value').then(snap => { const token = snap.child("token").val(); // Create a payload var payload = { data: { data_type: "direct_message", title: "Comment from" + sender_id, comment: comment, object_id: object_id, objecttype: objecttype, } }; // Sent To device with token Id : THIS IS LINE 29 return admin.messaging().sendToDevice(token, payload).then(response => { console.log("Successfully sent message:", response);}) .catch(error => {console.log("Error:", error); }); }); // token }); // onWrite
IT worked I just changed this // Sent To device with token Id return admin.messaging().sendToDevice(token, payload).then(result => { return console.log("Successfully sent message:", result); })
How can I get different types of notification?
I don't know how to send different types of notification to the device from Firebase cloud function in index.js I want to send (comments notification)(like notification). I am using this code to get following notification to device but I don't know how to get other. const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.sendNotification = functions.database.ref('/notification/{user_id}/{notification_id}').onWrite((change, context) => { const user_id = context.params.user_id; const notification_id = context.params.notification_id; console.log('We have a notification to send to : ', user_id); const fromUser = admin.database().ref(`/notification/${user_id}/${notification_id}`).once('value'); return fromUser.then(fromUserResult => { const from_user_id = fromUserResult.val().from; const from_message = fromUserResult.val().message; console.log('You have new notification from : ', from_user_id); const userQuery = admin.database().ref(`users/${from_user_id}/username`).once('value'); const deviceToken = admin.database().ref(`users/${user_id}/device_token`).once('value'); return Promise.all([userQuery,deviceToken]).then(result =>{ const userName = result[0].val(); const token_id = result[1].val(); const payload1 = { notification:{ title: "some is following you", body: `${userName} is following you`, icon: "default", click_action : "alpha.noname_TARGET_NOTFICATION" }, data:{ from_user_id:from_user_id } }; return admin.messaging().sendToDevice(token_id, payload1).then(result=>{ console.log("notification sent"); }); }) .then(response => { console.log('This was the notification Feature'); return true; }).catch(error => { console.log(error); //response.status(500).send(error); //any other error treatment }); }); });
You can change what you are sending to the /notification/${user_id}/${notification_id} node to include fields that will let you identify and create different notifications in the cloud function. For example, you could add a type field and then: return fromUser.then(fromUserResult => { const from_user_id = fromUserResult.val().from; const from_message = fromUserResult.val().message; const from_type = fromUserResult.val().type; Then you could build your notification based on type: if(from_type === NOTIFICATION_FOLLOW){ payload1 = { notification:{ title: "some is following you", body: `${userName} is following you`, icon: "default", click_action : "alpha.noname_TARGET_NOTFICATION" }, data:{ from_user_id:from_user_id } }; }else{ //set payload1 for a different notification } Add whatever fields are necessary for your payload and extend the control structure as needed.
cloud functions returning null for dataSnapshot
I am using cloud notifications for sending notifications whenever some data is updated in the realtime database, and I am sending the notificaations with some details which are also from the database const functions = require('firebase-functions'); const admin = require('firebase-admin'); admin.initializeApp(functions.config().firebase); exports.notifyUsers = functions.database.ref('/').onUpdate(event => { var message = event.data.val(); admin.database().ref('users/'+message.uid).on('value', function(dataSnapshot) { var usernameOfSender = dataSnapshot.child('username').val(); console.log('message: '+message.val()); console.log('dataSnapshot.val: '+dataSnapshot.val()); console.log('usernameOfSender: '+usernameOfSender); // Notification details. const text = message.message; const payload = { notification: { title: `${usernameOfSender} posted ${text ? 'a message' : 'an image'}`, body: text ? (text.length <= 100 ? text : text.substring(0, 97) + '...') : '', icon: dataSnapshot.child('profilePic').val() || '/images/defaultProfilePic.png', click_action: `https://${functions.config().firebase.authDomain}` } }; // Get the list of device tokens. return admin.database().ref('fcmTokens').once('value').then(allTokens => { if (allTokens.val()) { // Listing all tokens. const tokens = Object.keys(allTokens.val()); // Send notifications to all tokens. return admin.messaging().sendToDevice(tokens, payload).then(response => { // For each message check if there was an error. const tokensToRemove = []; response.results.forEach((result, index) => { const error = result.error; if (error) { console.error('Failure sending notification to', tokens[index], error); // Cleanup the tokens who are not registered anymore. if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') { tokensToRemove.push(allTokens.ref.child(tokens[index]).remove()); } } }); return Promise.all(tokensToRemove); }); } }); }); }); When I check my firebase console, this is what I get: usernameOfSender: null dataSnapshot.val: null message: [object Object] and the notification comes as null posted an image, with the default profile picture.