Adjusting a firebase cloud function - node.js

I am having trouble adjusting the code (using cors) for a firebase cloud function I am working on.
Below is the code for the function:
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as cors from "cors";
import { on } from "events"
const corsHandler = cors({origin: true});
admin.initializeApp();
exports.myFunc = functions.https.onRequest(function(req, resp) {
corsHandler(req, resp, async () => {
if (req.query.from !== undefined) {
const from = String(req.query.from);
functions.logger.log("From (URL):", from);
} else {
functions.logger.log("req.query.from is undefined");
}
const from = req.body.from;
functions.logger.log("Hello from --myFunc--");
admin.auth().getUserByEmail(from)
.then(function(userRecord) {
console.log("Successfully fetched user data:", userRecord.toJSON());
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
}); // End corsHandler.
});
When I call this function using this URL in the browser:
https://us-central1-myapp.cloudfunctions.net/myFunc?from=example#example.com
I get what I expect in the logs, that is:
myFunc: From (URL): example#example.com
On the other hand when I call the function using this Ajax code from a web-app:
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://us-central1-myapp. cloudfunctions.net/myFunc", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send("from=example#example.com");
xhr.onload = function() {
var data = JSON.parse(this.responseText);
console.log('THE DATA:',data);
};
I have a problem, getting the following in the web console logs:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://us-central1-myapp.cloudfunctions.net/myFunc. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 400.
I must be missing something. Can someone point out what it is ?

I finally got it to work, using this code for the Ajax call from the web-app (hoping this might help someone facing the same kind of issue at some point):
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://us-central1-myapp. cloudfunctions.net/ myFunc", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({
from: 'example#example.com'
}));
xhr.onload = function() {
var data = JSON.parse(this.responseText);
console.log('THE DATA:',data);
};

Related

Calling a firebase cloud function (with POST)

Here is the code for a working firebase cloud function and following is a question about some change I want to make and can't at this point, even after trying several options.
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as cors from "cors";
const corsHandler = cors({origin: true});
admin.initializeApp(functions.config().firebase);
exports.myFunc = functions.https.onRequest(function(req, resp) {
corsHandler(req, resp, async () => {
const from = String(req.query.from); // Through the URL.
// const from = req.body.from; // I tried this among other things to get the information through a POST but it did not work.
admin.auth().getUserByEmail(from)
.then(function(userRecord) {
console.log("Successfully fetched user data:",
userRecord.toJSON());
})
.catch(function(error) {
console.log("Error fetching user data:", error);
});
});
});
This function can be called using a URL like:
https://us-central1-myapp.cloudfunctions.net/myFunc?from=example#example.com
But what I want is to be able to call it through a POST from a JS page (with XMLHttpRequest) in my web app.
How should I change the function above for that?
For reference, this is the kind of code I am trying to use on the web-app side to call the cloud function (but it is not working):
var xhr = new XMLHttpRequest();
xhr.open("POST", "https://us-central1-myapp.cloudfunctions.net/myFunc", true, 'me#example.com', 'VerySecretPassWord');
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send({"from": "example#example.com"});
xhr.onload = function() {
var data = JSON.parse(this.responseText);
console.log('THE DATA:',data);
};

Undefined in console on GET request in NodeJS

I'm creating a script which is going to automatically receive data from API and store it in MongoDB at specific UTC time.
I use Node-Schedule for scheduling a task at specific time.
CoinMarketCap API for receiving a real time data.
Problem: I receive an undefined in console every second(since the node-schedule is configured to call the code every second). I was looking for any syntax errors or errors in API and wasn't successful. I understand that I receive undefined cause the function doesn't return anything.
Currently doesn't have any ideas what wrong with it at all.
All API keys and DB username password was correct I checked it as well.
Goal: To have the script which is automatically receives data from API and stores it MongoDB collection.
Full Code
const { MongoClient } = require('mongodb');
const schedule = require('node-schedule');
var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
const saveToDatabase = function(BTCdata) {
const url = 'mongodb+srv://name:password#cluster0-1kunr.mongodb.net/<dbname>?retryWrites=true&w=majority';
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, db) => {
if (err) throw err;
const dbo = db.db('Crypto');
const myobj = { Name: 'BTC', Volume: 'BTCdata' };
dbo.collection('Crypto-Values').insertOne(myobj, (error, res) => {
if (error) throw error;
console.log('1 document inserted');
db.close();
});
});
};
function request(method, url) {
return new Promise(((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = resolve;
xhr.onerror = reject;
xhr.send();
}));
}
const j = schedule.scheduleJob('* * * * * *', () => {
request(
'GET',
'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
)
.then((r1) => {
const x1 = JSON.parse(r1.target.responseText);
const BTCdata = x1.data.find((d) => d.symbol === 'BTC').quote.USD.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
})
.catch((err) => {
console.log(err);
});
});
EDIT1:
This is a console log of x1 value.
EDIT2:
Was missing this part -
var request = require('request');
After it was added I start receiving a new error in my console which is :
events.js:287
throw er; // Unhandled 'error' event
^
Error: Invalid URI "GET"
at Request.init
at new Request
at request
at Job.job
at Job.Invoke
at Users/path to node modules/node-schedule
at Timeout.onTimeout
EDIT3:
After correction to the code with #Sureshprajapati answer.
New error appears - TypeError: Cannot read property 'responseText' of undefined
Trying to find solution by myself. Still looking for any advice. Thank you.
var requestPromise = require('request-promise');
requestPromise.get({
uri: 'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
json: true
}).then(r1 => {
const x1 = JSON.parse(r1.target.responseText);
const BTCdata = x1.data.find(d => d.symbol === 'BTC').quote.USD
.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
}).catch(err => {
console.log(err);
});
request supports both streaming and callback interfaces natively. If you'd like request to return a Promise instead, you can use an alternative interface wrapper for request. These wrappers can be useful if you prefer to work with Promises, or if you'd like to use async/await in ES2017.
request-promise (uses Bluebird Promises)
This module is installed via npm:
npm install --save request
npm install --save request-promise
Coming to modifying your code as per documentation:
var requestPromise = require('request-promise');
requestPromise.get({
uri: 'http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=API-KEY-HERE',
json: true
}).then(x1 => {
const BTCdata = x1.data.find(d => d.symbol === 'BTC').quote.USD
.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
// Saving to database
saveToDatabase(BTCdata);
}).catch(err => {
console.log(err);
});

Request is not defined after installing request in nodejs

I'm creating a script which is going to receive a data from API every 24 hours in specific time.
I'm using node-schedule package
After I trying to see the script in terminal or in chrome console log. I receive an error that request is not defined.
I installed RequireJS already, but the error still appears.
I was trying the example from node-schedule documentation itself, also receiving the same error in terminal.
Where is my mistake and how I can fix it?
Code below:
var schedule = require("node-schedule");
var j = schedule.scheduleJob("*/55 20 * * *", function() {
request(
"GET",
"http://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?CMC_PRO_API_KEY=YOUR-API-KEY"
)
.then((r1) => {
var x1 = JSON.parse(r1.target.responseText);
var BTCdata = x1.data.find((d) => d.symbol === "BTC").quote.USD
.volume_24h; // creating a variable to store a BTC request from API
console.log(BTCdata);
})
.catch((err) => {
console.log(err);
});
});
function request(method, url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = resolve;
xhr.onerror = reject;
xhr.send();
});
}

Node and Twilio integration

I have written a programmable SMS feature using Twilio in nodejs. I have a message that has options to select and when user sends back any response I want to send an automated response using twilio.
I have completed all except after processing the response from user my automated response is not being delivered to user.
I keep getting above thing from my twilio dashboard.
Here is my response handler code..
app.post('/ui/sms',function(req, res) {
//req.headers['Content-type'] = 'text/xml';
//req.headers['Accept'] = 'text/xml';
try {
console.log('Processing Response', req.headers);
const MessagingResponse = require('twilio').twiml.MessagingResponse;
const twiml = new MessagingResponse();
const fromTwilio = isFromTwilio(req);
console.log('isFromTwilio: ', fromTwilio);
if (fromTwilio) {
let msg = req.body.Body||'';
if (msg.indexOf('1')>-1) {
twiml.message('Thanks for confirming your appointment.');
} else if (msg.indexOf('2')>-1) {
twiml.message('Please call 408-xxx-xxxx to reschedule.');
} else if (msg.indexOf('3')>-1) {
twiml.message('We will call you to follow up.');
} else {
twiml.message(
'Unknown option, please call 408-xxx-xxxx to talk with us.'
);
}
res.writeHead(200, { 'Content-Type': 'text/xml' });
res.end(twiml.toString());
}
else {
// we don't expect these
res.status(500).json({ error: 'Cannot process your request.' });
}
/*processSMSResponse(req, function(response) {
res.json(response);
});*/
} catch(e) {
res.json(e);
}
});
function isFromTwilio(req) {
console.log('REQ HEADER:::::::::\n', req);
// Get twilio-node from twilio.com/docs/libraries/node
const client = require('twilio');
// Your Auth Token from twilio.com/console
const authToken = 'xxxxxxxxxxxxxxxxx';
// The Twilio request URL
//const url = 'https://mycompany.com/myapp.php?foo=1&bar=2';
const url = 'https://xxxx.com/ui/sms';
var reqUrl = 'https://xxxx.com/ui/sms'
// The post variables in Twilio's request
//const params = {
//CallSid: 'CA1234567890ABCDE',
//Caller: '+14158675310',
//Digits: '1234',
//From: '+14158675310',
//To: '+18005551212',
//};
const params = req.body;
console.log('post params: ', params);
// The X-Twilio-Signature header attached to the request
try{
Object.keys(params).sort().forEach(function(key) {
reqUrl = reqUrl + key + params[key];
});
var twilioSignature = crypto.createHmac('sha1', authToken).update(Buffer.from(reqUrl, 'utf-8')).digest('base64');
//const twilioSignature = req.header('HTTP_X_TWILIO_SIGNATURE');
console.log('twilioSignature: ', twilioSignature);
} catch(e){
console.log(e);
}
return client.validateRequest(
authToken,
twilioSignature,
url,
params
);
}
I have explicitly tried setting headers but no use. I'm clue less on what twilio expects from me or how to modify headers.
{
"status": "Error",
"error": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Response><Message>Please call 408-xxx-xxxx to reschedule.</Message></Response>"
}
I see this as body in Twilio console and it has the response that I need but could not send as a message..
Twilio Developer Evangelist here.
From looking at your code and trying it myself I can't see anything generally wrong with it. There are two potential failing points here though:
1) I can't see your isFromTwilio function. If that one fails it might cause an error and then return JSON instead of XML on your error handler. I don't know why it would reply with the TwiML in that JSON though.
2) The other behavior I could reproduce (except that the TwiML is not being sent in the response body) is when I don't include body-parser in the middleware chain. This will cause req.body to be undefined and therefore req.body.Body will throw an error that is then being caught and JSON is being returned.
Do you have body-parser included and properly included as a middleware? You can either do it this way:
const { urlencoded } = require('body-parser');
app.use(urlencoded({ extended: false });
or if you only want to use it for this one endpoint you can add urlencoded({ extended: false }) as an argument before your request handler:
app.post('/ui/sms', urlencoded({ extended: false }), function(req, res) {
I hope this helps.
Cheers,
Dominik

Express API timeout despite success callback

I have an express API:
var bodyParser = require("body-parser");
app.use(bodyParser.json());
app.post("/adapter/mail", function(request, response) {
var body = request.body;
var id = body.id;
var params = {id: id};
Parse.Cloud.run("email", params, {
success: function(e) {
console.log("api: success");
respone.status(200).send("e");
},
error: function(e) {
console.log("api: error: " + JSON.stringify(e));
response.status(500).send(e);
}
});
});
Calling the API calls the Parse Cloud Code:
Parse.Cloud.define("email", function(request, response) {
console.log(JSON.stringify(request, null, 4));
response.success("ok");
});
In the console I see that console.log("api: success"); gets executed correctly, but the API request does not end, it times out despite the successful callback.
When Cloud Code returns response.error("error"); instead of response.success("ok"); the request does not timeout but ends immediately.
Why does the request time out on success?
Looks like you are missing an "s" on your callback
respon"s"e.status(200).send("e");

Resources