How can i get the information from [object Promise]?
I am using GCF (cloud function) to process square payments.
As of right now I am getting back a response of { response="OK:[object Promise]" }
This is processing the cloud function on the cloud platform:
const functions = require('firebase-functions');
const SquareConnect = require('square-connect');
const crypto = require('crypto');
exports.fxtest = functions.https.onCall((data, context) => {
const defaultClient = SquareConnect.ApiClient.instance;
defaultClient.basePath = "https://connect.squareupsandbox.com";
const oauth2 = defaultClient.authentications['oauth2'];
oauth2.accessToken = 'sandbox-token-ommitted';
const idempotency_key = crypto.randomBytes(23).toString('hex');
const payments_api = new SquareConnect.PaymentsApi();
const item_source = data.source_id;
const item_price = 1.00;
const item_currency = 'USD';
const request_body = {
"idempotency_key": idempotency_key,
"source_id": item_source,
"amount_money": {
"amount": item_price,
"currency": item_currency
}
};
var rsp;
try{
const response = payments_api.createPayment(request_body)
.then(
r=> { return r; })
.catch(
e => { return e; });
const json = JSON.stringify('OK:' + response);
rsp = json;
} catch(error){
return rsp = 'ERROR:' + error;
}
return{
response: rsp
};
});
This is the processing the returned data on an Android device:
private FirebaseFunctions mFunctions;
private Task<HttpsCallableResult> fxtest(String text, Context ctx, CardDetails crds){
Map<String, Object> data = new HashMap<>();
data.put("source_id",crds.getNonce());
return this.mFunctions.getHttpsCallable("fxtest").call(data)
.addOnCompleteListener((Activity) ctx, new OnCompleteListener<HttpsCallableResult>() {
#Override public void onComplete(#NonNull Task<HttpsCallableResult> task) {
Toast.makeText(ctx, "result: " + task.getResult().getData(),Toast.LENGTH_LONG).show();
}
});
}
Some sources i was looking at:
connect-api-example using nodejs on github
square-conect on npm
I've found the solution to the question, basically my "credentials access token was using authorization access token" that was the first mistake, the other was due to the itempotency key which has a max limit of 45 characters according to the API reference square connect api, and the other was how i returned the response which is meant to be in JSON format as far as the promise i consumed was doing. Here is the source code, (the java is fine, no need to edit that) it was only on the nodejs side. The API keys are referenced in the environmental variables side on the GCF platform. This will effectively allow processing a square payment through android applications using "serverless approach".
const functions = require('firebase-functions');
const SquareConnect = require('square-connect');
const crypto = require('crypto');
exports.fxtest = functions.https.onCall(async (data, context) => {
/* testing url for sandbox */
//defaultClient.basePath = process.env.TESTING_SQUARE_CONNECT_URL;
const defaultClient = SquareConnect.ApiClient.instance;
defaultClient.basePath = process.env.PRODUCTION_SQUARE_CONNECT_URL;
const oauth2 = defaultClient.authentications["oauth2"];
oauth2.accessToken = process.env.PRODUCTION_APPLICATION_ACCESS_TOKEN;
const idempotency_key = crypto.randomBytes(16).toString("hex");
const payments_api = new SquareConnect.PaymentsApi() ;
/* value of amount is in cents as of 11/29/2019
, 1 is equal to 1 cent, 100 is equal to 100 cents */
const request_body = {
"idempotency_key": idempotency_key,
"source_id": data.source_id,
"amount_money": {
"amount": 100,
"currency": "USD"
},
};
try{
response = await payments_api.createPayment(request_body)
.then(
r=> {
if(r.ok) { return Promise.resolve(r); }
return Promise.reject(Error("TRY ERROR_ON_RESPONSE: " + JSON.stringify(r)))
})
.catch(
e=> {
return Promise.reject(Error("TRY ERROR_ON_EXCEPTION: " + JSON.stringify(e)))
});
return "TRY OKAY: " + JSON.stringify(response);
} catch(error){
return "CATCH ERROR: " + JSON.stringify(error);
}
});
Related
I'm trying to call an external POST API from my firebase function but it's not working as expected. I'm calling the firebase function from my android app. Following are the code snippets for my function, android call and the error that I'm getting in firebase console:
Firebase Function:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const https = require('https');
admin.initializeApp(functions.config().firebase);
exports.generateToken = functions.https.onCall((data, context) => {
const variable = data.variable;
const uid = context.auth.uid;
console.log("Function Trigerred");
if(uid !== null) {
console.log("UID: " + uid);
const requestPayload = JSON.stringify({
"variable": variable
});
console.log(requestPayload);
const config = {
hostname: 'API-HOST',
port: 443,
path: '/API-PATH',
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
};
console.log(config);
const response = "";
const req = https.request(config, (res) => {
res.on('data', (data) => {
console.log(data);
res.send(data);
});
});
req.on('error', (error) => {
console.log(error);
res.end(error);
});
req.write(requestPayload);
req.end();
} else {
console.log("Invalid User");
res.send("Invalid User");
}
});
Call in App
Map<String, Object> data = new HashMap<>();
data.put("variable", "value");
FirebaseFunctions.getInstance()
.getHttpsCallable("generateToken")
.call(data)
.continueWith(task -> {
String result = (String) task.getResult().getData();
Log.e("1: ", result);
return result;
})
.addOnCompleteListener(task -> {
Log.e("2: ", "Complete");
if (!task.isSuccessful()) {
Exception e = task.getException();
if (e instanceof FirebaseFunctionsException) {
FirebaseFunctionsException ffe = (FirebaseFunctionsException) e;
FirebaseFunctionsException.Code code = ffe.getCode();
Object details = ffe.getDetails();
}
Log.e("3: ", task.getException().toString());
}
});
Firebase Console Log
{
Error: getaddrinfo ENOTFOUND API-HOST API-HOST:443 at GetAddrInfoReqWrap.onlookup [as oncomplete (dns.js:67:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'API-HOST',
host: 'API-HOST',
port: 443
}
However, when I tried hitting this API from Postman, I got the successful response.
I'm new to Node.js.
I am creating an App Where user can buy coins and for that I have been trying to integrate Razorpay into my Android App since a long time now. Razorpay can directly be used in Android. It sends Success or Failure results for payment and I can act accordingly (adding points to database in this case). But the problem with this approach is that I have to write points (after success) to database from the app. Which means I have to give write access for points node to user app which is not a good idea. So I wanted to use Razorpay with Firebase Cloud Functions and searching for a long time I came across this tutorial which is for web. I am quite new to Cloud Functions and hence wanted a little help for Android.
Here is the Index.js code but For Web
const functions = require("firebase-functions");
var express = require("express");
var cors = require("cors");
var request = require("request");
const crypto = require("crypto");
const key = "----insert yout key here----";
const key_secret = "----- insert key secret here ----";
var app = express();
app.use(cors({ origin: true }));
app.post("/", (req, res) => {
const amount = req.body.amount;
//Allow Api Calls from local server
const allowedOrigins = [
"http://127.0.0.1:8080",
"http://localhost:8080",
"https://-------YourFirebaseApp-----.firebaseapp.com/"
];
const origin = req.headers.origin;
if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader("Access-Control-Allow-Origin", origin);
}
var options = {
method: "POST",
url: "https://api.razorpay.com/v1/orders",
headers: {
//There should be space after Basic else you get a BAD REQUEST error
Authorization:
"Basic " + new Buffer(key + ":" + key_secret).toString("base64")
},
form: {
amount: amount,
currency: "INR",
receipt:
"----- create a order in firestore and pass order_unique id here ---",
payment_capture: 1
}
};
request(options, function(error, response, body) {
if (error) throw new Error(error);
res.send(body);
});
});
app.post("/confirmPayment", (req, res) => {
const order = req.body;
const text = order.razorpay_order_id + "|" + order.razorpay_payment_id;
var signature = crypto
.createHmac("sha256", key_secret)
.update(text)
.digest("hex");
if (signature === order.razorpay_signature) {
console.log("PAYMENT SUCCESSFULL");
res.send("PAYMENT SUCCESSFULL");
} else {
res.send("something went wrong!");
res.end();
}
});
exports.paymentApi = functions.https.onRequest(app);
I think this will help you.
In my case, I am accessing items(Array of Product IDs) from the user's cart and reading the current price of the items then passing it as an argument to SendOrderId function which will return an OrderId to proceed.
The important thing to keep in mind is that you must have added razorpay in your dependencies inside package.json. You can do that by simply running
npm i razorpay
inside your functions folder (Which include index.js) which will automatically add the dependency to your project
const functions = require("firebase-functions");
const admin = require('firebase-admin');
const Razorpay = require('razorpay')
const razorpay = new Razorpay({
key_id: 'Your_razorpay_key_id',
key_secret: 'your_secret'
})
admin.initializeApp();
function SendOrderId(amountData, response) {
var options = {
amount: amountData, // amount in the smallest currency unit
currency: "INR",
};
razorpay.orders.create(options, function(err, order) {
console.log(order);
response.send(order);
});
}
exports.getOrderId = functions.https.onRequest((req, res) => {
return admin.firestore().collection('Users').doc(req.query.uid).get().then(queryResult => {
console.log(queryResult.data().Cart);
admin.firestore().collectionGroup("Products").where('ProductId', 'in', queryResult.data().Cart).get().then(result => {
var amount = 0;
result.forEach(element => {
amount += element.data().price;
});
SendOrderId(amount * 100, res);
})
})
});
I have used dialogflow fulfillment to get data from an external api. It works fine with the test console. But on being deployed on to an android app, it gives a blank response. How do I fix this? Thanks.
The code in fulfillment:
'use strict';
const axios = require('axios');
const functions = require('firebase-functions');
const {WebhookClient} = require('dialogflow-fulfillment');
const {Card, Suggestion} = require('dialogflow-fulfillment');
process.env.DEBUG = 'dialogflow:debug'; // enables lib debugging statements
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
const agent = new WebhookClient({ request, response });
console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
function welcome(agent) {
agent.add(`Welcome to my agent!`);
}
function fallback(agent) {
agent.add(`I didn't understand`);
agent.add(`I'm sorry, can you try again?`);
}
function rhymingWordHandler(agent){
const word = agent.parameters.word;
agent.add(`Here are the rhyming words for ${word}`);
return axios.get(`https://api.datamuse.com/words?rel_rhy=${word}`)
.then((result) => {
result.data.map(wordObj => {
agent.add(wordObj.word);
});
});
}
let intentMap = new Map();
intentMap.set('Default Welcome Intent', welcome);
intentMap.set('Default Fallback Intent', fallback);
intentMap.set('Rhyme Scheme', rhymingWordHandler);
agent.handleRequest(intentMap);
});
The code in MainActivity.java
public void callback(AIResponse aiResponse) {
if (aiResponse != null) {
// process aiResponse here
String botReply = aiResponse.getResult().getFulfillment().getSpeech();
Log.d(TAG, "Bot Reply: " + botReply);
showTextView(botReply, BOT);
} else {
Log.d(TAG, "Bot Reply: Null");
showTextView("There was some communication issue. Please Try again!", BOT);
}
}
I am trying to send notifications to an Android app's users with firebase cloud messaging. I am using cloud firestore triggers but when trying to access a user node's properties, they are undefined.
Here is my index.js :
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.notifyNewMessage = functions.firestore
.document('conversations/{conversation}/messages/{message}')
.onCreate((docSnapshot, context) => {
const message = docSnapshot.data();
const recipientId = message['recipientId'];
const senderName = message['senderName'];
return admin.firestore().collection("users").doc(recipientId).get().then(userDoc => {
const registrationTokens = userDoc.registrationTokens;
console.log("registrationTokens = "+ registrationTokens);
const notificationBody = message['message'];
const payload = {
notification : {
title : senderName + " sent you a message,",
body: notificationBody,
clickAction: "ConversationActivity"
},
data : {
contactName : senderName,
userId : message['senderId']
}
}
return admin.messaging().sendToDevice(registrationTokens, payload).then(response => {
const stillRegisteredTokens = registrationTokens;
response.results.forEach((result, index) => {
const error = result.error;
if (error){
const failedRegistrationToken = stillRegisteredTokens['index'];
if (error.code === 'messaging/invalid-registration-token'
|| error.code === 'messaging/registration-token-not-registered') {
const failedIndex = stillRegisteredTokens.indexOf(failedRegistrationToken)
if (failedIndex > -1) {
stillRegisteredTokens.splice(failedIndex, 1);
}
}
}
})
return admin.firestore().doc("users/" + recipientId).update({
registrationTokens: stillRegisteredTokens
})
})
})
})
Because of that I get an error "sendDevice() argument must be non-empty array or non null string"
UPDATE
registrationTokens were undefined because I called userDoc instead of userDoc.data()
Now registrationTokens is not null nor empty but I still get the error :
Registration token(s) provided to sendToDevice() must be a non-empty string or a non-empty array.
"Server Error" in nodejs api (android to web server request)
I am a new node.js learner. I'm doing a project that user are registration by android application, and user details will go to web server. but when i send request to web server by API that time show "Server Error Problem". but when i send data by (postman row data) that time it works, but if i send by (postman form-data) that time it not work, and show "Server Error Problem".
In addition, I am using a shared linux Server supported by cpanel and CloudLinux.
-----------------------
index.js file
------------------------
const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const cors = require('cors');
const verifyToken = require('./jwt/verify/verifytoken');
const mysql = require('mysql');
global.config = require('./jwt/config/config');
const extInfo = require('./info/extInfo');
const port = process.env.PORT || 3000;
const connection = mysql.createConnection({
host: "localhost",
user: “abcd”,
password: "123345",
database: “xyz”
});
var point = 0;
const app = express();
app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));
app.use(express.json());
app.use(bodyParser.urlencoded({extended : false}));
app.use(cors());
app.use('/api/v1', require('./api/v1'));
------------------------------------
api file (code)
---------------------------
const express = require('express');
const router = express.Router();
const mysql = require('mysql');
var error = ["error", "error", "error"];
const connection = mysql.createConnection({
host: "localhost",
user: “abcd”,
password: “12345”,
database: “xyz”
});
router.get('/login?', (req , res) => {
var studentdata = {
A: req.query.a,
B: req.query.b
}
connection.query(`Select Student_id from student where Mobile = ${a} and Password = ${b}`, (err, result, fields) => {
if (err) {
console.log("error");
res.send(error);
} else if (result.length < 1){
console.log("error");
res.send(err);
}
return res.send(result);
let Student_id = result[0].Student_id ;
connection.query(`SELECT * FROM B where A = ${A}`, (err1, result1, fields1) => {
if(err1){
res.send(err1);
} else if (result1.length < 1){
res.send(error);
}
res.send(result1);
});
});
});
router.post('/registration', (req , res) => {
let newStudent = {
a : req.body['a'],
b: req.body.b,
....
c: req.body.c
}
connection.query(`SELECT * FROM d1 where Mobile = ${a}`, (err, result , fields) => {
if(err) {
return res.send("Server Error");
} else if (result.length > 0) {
return res.send("wrong phone");
}
connection.query(`INSERT INTO d1 (Student_name, School , ..... , Password ) VALUES ('${newStudent.student_name}', ..... , '${newStudent.student_password}')`, (err1, result1, fields1) => {
if(err1) {
return res.send(error);
} else if (result1.length > 0) {
return res.send("wrong phone");
}
let insertId = result1.insertId;
// Create Score table Account
connection.query(`INSERT INTO d2( A ) VALUES ('${insertId}')`, (err2, result2, fields) => {
if (err2) {
return res.send(err2);
}
return res.send("Registration Successful");
});
})
});
});
router.get('*', (req , res) => {
res.send({"info" : "Nothing Found"});
});
module.exports = router ;