How to get receipt-data from Post request in Node.js - javascript

I'm trying to send a receipt to my Node.js server. At the moment It prints out the receipt-data in firebase which indicates its gotten it from the POST request I sent from my iOS App. However i can't pass properly in my code to be validated in const receipt = request.body;. How can I pass it along in the correct way?. Thanks.
exports.receiptValidation = functions.https.onRequest((request, response) => {
const receipt = request.body;
console.log(receipt);
iap.config({
applePassword: 'MySharedAppleKey',
test: true
});
iap.setup((error) => {
if (error) {
console.log('Failed to validate receipt', error);
}
});
iap.validate(receipt).then((pResponse) => {
//Check if receipt is valid
if (iap.isValidated(pResponse)) {
console.log('The receipt is valid', pResponse);
response.send(pResponse);
}
return pResponse;
})
.catch((error) => {
console.log(`Sorry couldn't validate receipt`, error);
response.send(error);
return error
});
});
Here is my output in Firebase. I'm using a firebase function

I solved it by changing my receipt-data string in both Swift and Server code
Swift
let receiptData = receipt!.base64EncodedString()
let requestReceiptDict = ["receipt": receiptData]
Node.js
const receipt = request.body.receipt;
console.log(receipt);

Related

I'm unable to send a response to my react.js using http.get in node

I'm trying to get the temperature data from my node.js backend sent to react.js but i kept getting res.send is not a funtion
Sample code here
app.get("/gettemperature", (req, res) => {
const email = req.query.email;
let stmt = `SELECT * FROM users WHERE email=?`;
let todo = [email];
db.query(stmt, todo, (err, results, fields) => {
if (err) {
console.error(err.message);
}
if(results.length > 0 ){
let id = results[0].id;
let getID = `SELECT * FROM controlModules WHERE deviceowner=?`;
let getidData = [id];
db.query(getID, getidData, (err, resulta, fields) => {
if (err) {
console.error(err.message);
}
if(resulta.length > 0){
let lanip = resulta[0].ipaddress;
let url = "http://"+lanip+"/data";
http.get(url,(res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
try {
let json = JSON.parse(body);
const temp_actual = json.temperature.value;
console.log(temp_actual);
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
value: temp_actual
})
);
} catch (error) {
console.error(error.message);
};
});
}).on("error", (error) => {
console.error(error.message);
});
}
});
}
});
});
i really need to return/send/respond the temperature data to my front end but i'm getting said error, is there a different way to return data?
It looks like you are mixing up an HTTP server you wrote in Node (although you haven't shown any relevant code) and an HTTP client you also wrote in Node.
res is an argument received by the callback you pass to http.get and contains data about the response received by your HTTP client.
Meanwhile, somewhere else (not shown) you have a different variable also called res which is the object your HTTP server uses to send its response to the browser running your React code.
You are calling res.send and wanting res to be the latter but it is really the former.
Since you haven't shown us the HTTP server code, it is hard to say where that res is, but there is a good chance you have shadowed it and can solve your problem by using different names (e.g. client_res and server_res).
That said. I strongly recommend avoiding using the http module directly as the API follows out of date design patterns and isn't very friendly. Consider using fetch or axios for making HTTP requests and Express.js for writing HTTP servers.

How to hold a node api execution till a db query does not return null

Seems rather like an unwanted requirement for a piece of code but in my case this is exactly what I need. I have an api (API-1) that interacts with a third party service. This third party service instead of directly giving me a response that I can forward back to frontend is giving me response on API-2 (With a webhook listener endpoint). I'm saving this API-2 response that I get by listening to the webhook in my database. Now I somehow need this response which is now sitting idol in my database in my API-1 so that I can forward it back to the frontend. If I query the database right away during the flow of the API-1 (Just after consume the third party service API), I'll get null as API-2 is getting the response asynchronously with a webhook (Mostly a gap of 1-2 seconds). So I somehow need to figure out an easy way to await/hold the API-1 flow till the database does not return null/returns back the response I saved from API-2 in the database. I'm not sure if the gap will always be 1-2 seconds hence I can't be using setTimeout for this.
//API-1
const sendPaymentRequest = async (req, res) => {
try {
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data);
//Check result i.e response from http listener
const webhookResponse = await MpesaModel.findOne({
conversationId: data.ConversationID
});
console.log('Webhook response => ', webhookResponse); //This is null
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//API-2 - This is the webhook which receives the response
const saveWebhookB2C = async (req, res) => {
const { Result } = req.body;
//console.log('Mpesa webhook data received => ', Result);
let saveResponse = new MpesaModel({
...Result,
});
const result = await saveResponse.save();
console.log('B2c mpesa to kenya saved in db => ', result);
res.status(200).send();
};
Just wait until the response is different than null:
let webhookResponse = null;
while (response === null) {
await sleep(1000);
webhookResponse = await MpesaModel.findOne({
conversationId: data.ConversationID,
});
}
The sleep function should be fairly simple (and we use it only to wait one second until the next query):
const sleep = (timeInMilliseconds) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(), timeInMilliseconds);
});
};
Note: the while loop will run forever if the answer is always null, so probably you want to add another condition to the while in case the result is always null (maybe a maximum number of tries?).
async function getNotNullResponse({conversationId}){
const webhookResponse = await MpesaModel.findOne({conversationId});
return webhookResponse || getNotNullResponse({conversationId});
}
//API-1
const sendPaymentRequest = async (req, res) => {
try {
const payment_reponse = await axios.post(url, body, config);
const { data } = payment_reponse;
console.log("Payment request => ", data);
//Check result i.e response from http listener
const webhookResponse = await getNotNullResponse({
conversationId: data.ConversationID
});
console.log('Webhook response => ', webhookResponse); //This is not null
res.status(200).json({ message: "Send money request", data });
} catch (error) {
console.log("Error while making a payment request", error);
res
.status(400)
.json({ message: "Error while send payment request", error: error.data });
}
};
//API-2 - This is the webhook which receives the response
const saveWebhookB2C = async (req, res) => {
const { Result } = req.body;
//console.log('Mpesa webhook data received => ', Result);
let saveResponse = new MpesaModel({
...Result,
});
const result = await saveResponse.save();
console.log('B2c mpesa to kenya saved in db => ', result);
res.status(200).send();
};

Trying to subscribe to topic on Firebase Cloud Messaging gives Error

When i try to subscribe to a topic i get the following error:
.subscribeToTopic is not a function
const messaging = firebase.messaging();
messaging
.requestPermission()
.then(() => {
return messaging.getToken();
})
.then(token => {
messaging
.subscribeToTopic(token, 'allUsers')
.then(response=> {
console.log(JSON.stringify(response));
})
.catch(function(error) {
console.log('Error subscribing to topic:', error);
});
})
.catch(err => {
console.log('Unable to get permission to notify.', err);
});
If I remove that line of .subscribeToTopic and add a POST call via http it works using the following url:
https://iid.googleapis.com/iid/v1/TOKEN/rel/topics/TOPIC_NAME
I took a look to this question and the docs
Cloud Messaging in Cloud Functions: admin.messagin(...).send is not a function
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging
ah i solved it by handling on backend side ( nodeJS ) where the documentation is easy to handle topic.
so in this case we have alr generate token on frontend side then in backend (nodeJS) we tried to subscribe to topic by the token.
so in frontend end when we stream or firebase.messaging().onMessage(payload => { would like to trigger and show the message by topic.
FYI : https://github.com/firebase/firebase-js-sdk/issues/5289#issuecomment-899542765
so from the link we know that
Notification.vue
// these from frontend side ( for example vueJS )
import firebase from 'firebase/app'
import 'firebase/messaging'
// firebase only for get token, onMessaging, request permission check, there is no function to subscribe topic by the token, so we handle on backend side my alternative
then in server.js
// these from backend side ( for examle nodeJS )
const { admin } = require('./firebase-config');
// admin.messaging().sendToTopic()
// admin.messaging().subscribeToTopic()
// admin.messaging().sendToDevice()
if you are looking for the firebase-config.js here is
/*
* Initialize firebase
*/
var admin = require("firebase-admin");
var serviceAccount = require("./firebase.json"); // you can get the .json file on firebase service account .
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://project-xxxxxxx.firebaseio.com"
});
module.exports.admin = admin
my implementation :
app.get('/firebase/notification', (req, res)=>{
const registrationToken = req.body.registrationToken;
admin.messaging().subscribeToTopic(registrationToken, 'myTopic')
.then(response => {
console.log('Successfully subscribed to topic:', response)
const options = notification_options;
const message_notification = {
notification: {
title: 'Yogi Arif Widodo',
body: '2 10 pm',
url: 'https://localhost:8080',
other: 'other data',
}
};
admin.messaging().sendToTopic('myTopic', message_notification, options).then( response => {
so when i tested on firebase console send by topic myTopic my Notification.vue trigger these code
firebase.messaging().onMessage(payload => {
.....console.log
}
You need to use the method send not sendToTopic:
// The topic name can be optionally prefixed with "/topics/".
var topic = 'highScores';
var message = {
data: {
score: '850',
time: '2:45'
},
topic: topic
};
// Send a message to devices subscribed to the provided topic.
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);
});
send() was released and replaced sendtotopic/sendtodevice in version FCM v1
https://firebase.googleblog.com/2018/02/firebase-cloud-messaging-v1-now.html
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging

Why my firebase cloud function process never finished?

I have this function for testing sending notification to all users.
export const sendTestingNotification = functions.https.onRequest((request, response) => {
const message = "Hello world";
const body = "This is body"
const getAllUsersPromise = admin.database().ref('/users').once('value')
const payload = {
notification: {
title: message,
body: body
}
}
return getAllUsersPromise.then(results => {
var tokens : string[] = [];
console.log("Child Snapshot count: ", results.numChildren())
results.forEach(childSnapshot => {
var childData = childSnapshot.val();
var instanceId = String(childData.instanceId)
if (childData.instanceId != null) { tokens.push(instanceId); }
})
console.log('final tokens = ',tokens," notification= ",payload);
return admin.messaging().sendToDevice(tokens, payload).then(response2 => {
console.log ("Done sending notification call. Entering callback.")
const tokensToRemove : string[] = [];
response2.results.forEach ((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to instance id = ', tokens[index], error);
}
else {
console.log("Successfully send notification to ", tokens[index])
}
});
return Promise.all(tokensToRemove);
})
.catch(console.log.bind(console));
})
.catch(console.log.bind(console));
});
I have only one user in firebase database, and that one user has instanceId.
Here's the console log:
Child Snapshot count: 1
final tokens = [ 'eMZHr5WgHmU:APA91bEKg8wAS5qYMxuSJqn...
Done sending notification call. Entering callback.
Successfully send notification to eMZHr5WgHmU:APA91bEKg8wAS5qYMxuSJqn...
Function execution took 60002 ms, finished with status: 'timeout'
What's left of my function execution so that it finishes properly? The browser that call the function never stops show loading indicator.
If I add a response.send before return Promise, the browser loading finished. But checking at the log showed me that the process still working and returned the "Function execution took 60002 ms, finished with status: 'timeout'" error. How can I fix this?
With HTTP type functions, you need to send a response to the caller to terminate the function. For all code paths in your function, you should be calling response.send() or something that will send that response. Please consult the documentation for more information an examples. In particular, read the section on terminating a function.

How to add results from a promise based API call with message.addReply using Recast.ai?

I'm making a bot that searches restaurants based on location. Can anyone help me why this doesnt show up in FB messenger?:
restaurants(result.getMemory('location').raw)
.then(res=>{
message.addReply(res);
message.reply();
});
}
The call to the restaurants function returns the results from a YELP API call (an array of restaurants) but when I add it as a reply to message, nothing happens in FB messenger.
Here is the full code for message.js:
const recastai = require('recastai');
const restaurants = require('./restaurants');
// This function is the core of the bot behaviour
const replyMessage = (message) => {
// Instantiate Recast.AI SDK, just for request service
const request = new recastai.request(process.env.REQUEST_TOKEN,
process.env.LANGUAGE);
// Get text from message received
const text = message.content;
console.log('I receive: ', text);
// Get senderId to catch unique conversation_token
const senderId = message.senderId;
// Call Recast.AI SDK, through /converse route
request.converseText(text, { conversationToken: senderId })
.then(result => {
//Recast takes text analyses that, returns a result object, generates replies adds messages to reply stack and then sends the replies
//Call Yelp API with when the intent is Location. When Yelp returns result we add it to the result.replies array.
//Then we add everything in result.replies to the messaging queue that sends the responses to FB
if (result.action) {
console.log('The conversation action is: ', result.action.slug);
}
// If there is not any message return by Recast.AI for this current conversation
if (!result.replies.length) {
message.addReply({ type: 'text', content: 'I don\'t have the reply to this yet :)' });
} else {
// Add each reply received from API to replies stack
result.replies.forEach(replyContent => message.addReply({ type: 'text', content: replyContent }));
}
// Send all replies
message.reply()
//send initial reply generated by Recast first
.then(() => {
//call restaurant function that returns a list of results from API
//if the action is location and done
if(result.action && result.action.slug === 'location' && result.action.done){
restaurants(result.getMemory('location').raw)
.then(res=>{
console.log(res);
message.addReply(res);
message.reply();
});
}
})
.catch(err => {
console.error('Error while sending message to channel', err);
});
})
.catch(err => {
console.error('Error while sending message to Recast.AI', err);
});
};
module.exports = replyMessage;
And here is my restaurants.js code that is imported into the message.js file for the bot behavior:
const rp = require('request-promise');
// Load configuration
require('./config');
const restaurants = (location) => {
return Promise.all([
yelpCall(location)
]).then(result => {
//result contains the return value from Yelp call
return result;
});
};
const yelpCall = (location) => {
const auth = {
method: 'POST',
url: 'https://api.yelp.com/oauth2/token?grant_type=client_credentials&client_id='+ process.env.YELP_APP_ID +'&client_secret='+process.env.APP_SECRET
};
return rp(auth)
.then(result => {
const tokens = JSON.parse(result);
return tokens;
})
.then(result=>{
const options = {
url: 'https://api.yelp.com/v3/businesses/search?location=' + location + "&term=thai",
headers: {Authorization: "Bearer " + result.access_token}
};
return rp(options).then(findings =>{
return findings;
});
});
};
module.exports = restaurants;
A few thoughts :
message.reply is thenable, therefore return message.reply() in two places.
request.converseText() is thenable, therefore return request.converseText(...).
restaurants is thenable, therefore return restaurants(...).
in message.js, message.addReply() is passed object of the form {type:..., content:...} in two places but finally just res. Is that correct?
in restaurants.js, Promise.all() appears to be unnecessary. It will cause its result to be wrapped in an array. module.exports = location => yelpCall(location); seems more appropriate.

Categories

Resources