Almost there, but for some reason my HTTP post request isn't firing and eventually the function timesout. Completely beside myself and posting my code to see if anyone picks up on any noob moves that I'm completely missing. NOTE: the database write completes so I'm assuming that the HTTP Post request isn't firing, is that a safe assumption? Or JS is a different beast?
exports.stripeConnect = functions.https.onRequest((req, res) => {
var code = req.query.code;
const ref = admin.database().ref(`/stripe_advisors/testing`);
var dataString = `client_secret=sk_test_example&code=${code}&grant_type=authorization_code`;
var options = {
url: 'https://connect.stripe.com/oauth/token',
method: 'POST',
body: dataString
};
function callback(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
}
}
request(options, callback);
return ref.update({ code: code });
});
I understand that you want to POST to https://connect.stripe.com/oauth/token by using the request library and, on success, you want to write the code value to the database.
You should use promises, in your Cloud Function, to handle asynchronous tasks. By default request does not return promises, so you need to use an interface wrapper for request, like request-promise
Therefore, the following should normally do the trick:
.....
var rp = require('request-promise');
.....
exports.stripeConnect = functions.https.onRequest((req, res) => {
var code = req.query.code;
const ref = admin.database().ref('/stripe_advisors/testing');
var dataString = `client_secret=sk_test_example&code=${code}&grant_type=authorization_code`;
var options = {
url: 'https://connect.stripe.com/oauth/token',
method: 'POST',
body: dataString
};
rp(options)
.then(parsedBody => {
return ref.update({ code: code });
.then(() => {
res.send('Success');
})
.catch(err => {
console.log(err);
res.status(500).send(err);
});
});
Related
I am working on the Zoom API now. I want to send my token from ZOOM API to front-end as a response. However, "token from request" is always printed first and undefined! Then the token from Zoon API" will be followed with the token. How can I make it happen? Thx!
const Newrequest = require("request");
class ZoomController {
async getInvLink({ request, response }) {
const instructor_id = params.id;
try {
let tokenRes;
const code = request.all().code;
console.log("the code from frontend is ", code);
const client_id = _something_
const client_secret = _something_
var options = {
method: "POST",
url: "https://api.zoom.us/oauth/token",
qs: {
grant_type: "authorization_code",
code: code,
redirect_uri: _something_
},
headers: {
Authorization:
"Basic " +
Buffer.from(client_id + ":" + client_secret).toString("base64")
}
};
await Newrequest(options, function(error, res, body) {
if (error) throw new Error(error);
tokenRes = JSON.parse(body);
console.log("token from Zoon API",tokenRes);
});
console.log("token from request",tokenRes);
return response.status(200).send(tokenRes);
} catch (error) {
console.log(error);
return response.status(401).send();
}
I have no idea what this api is, but I'm going to make an educated guess that Newrequest doesn't return a promise. So awaiting it isn't actually what you want to do.
What you can do, however, is use some simple code to turn it into a promise:
const tokenRes = await new Promise((resolve, reject) => {
Newrequest(options, function(error, res, body) {
if (error) reject(error);
tokenRes = JSON.parse(body);
console.log("token from Zoon API",tokenRes);
resolve(tokenRes);
});
})
You would have to listen to an endpoint at something and you will receive the code over there. This is the code you can send to exchange for an access token.
Please consult this link : https://www.npmjs.com/package/request#promises--asyncawait
You can convert a regular function that takes a callback to return a promise instead with util.promisify()
Example :
Newrequest(options, function(error, res, body) {
if (error) throw new Error(error);
tokenRes = JSON.parse(body);
console.log("token from Zoon API",tokenRes);
});
// to
const util = require('util');
const req = util.promisify(Newrequest)
const data = await req(options)
// ...
It's a sample code. Please adapt with your needs
Useful course : https://masteringjs.io/tutorials/node/promisify
Request library is deprecated
It would be interesting to use another library.
Alternatives :
Got
Axios
Node-fetch
superagent
Almost there, but for some reason my HTTP post request isn't firing and eventually the function timesout. Completely beside myself and posting my code to see if anyone picks up on any noob moves that I'm completely missing. NOTE: the database write completes so I'm assuming that the HTTP Post request isn't firing, is that a safe assumption? Or JS is a different beast?
exports.stripeConnect = functions.https.onRequest((req, res) => {
var code = req.query.code;
const ref = admin.database().ref(`/stripe_advisors/testing`);
var dataString = `client_secret=sk_test_example&code=${code}&grant_type=authorization_code`;
var options = {
url: 'https://connect.stripe.com/oauth/token',
method: 'POST',
body: dataString
};
function callback(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(body);
}
}
request(options, callback);
return ref.update({ code: code });
});
I understand that you want to POST to https://connect.stripe.com/oauth/token by using the request library and, on success, you want to write the code value to the database.
You should use promises, in your Cloud Function, to handle asynchronous tasks. By default request does not return promises, so you need to use an interface wrapper for request, like request-promise
Therefore, the following should normally do the trick:
.....
var rp = require('request-promise');
.....
exports.stripeConnect = functions.https.onRequest((req, res) => {
var code = req.query.code;
const ref = admin.database().ref('/stripe_advisors/testing');
var dataString = `client_secret=sk_test_example&code=${code}&grant_type=authorization_code`;
var options = {
url: 'https://connect.stripe.com/oauth/token',
method: 'POST',
body: dataString
};
rp(options)
.then(parsedBody => {
return ref.update({ code: code });
.then(() => {
res.send('Success');
})
.catch(err => {
console.log(err);
res.status(500).send(err);
});
});
I have the following server.js get route
app.get('/', function(req, res) {
var url;
var final_res = [];
endpoints.forEach(function(url){
request(url, function(error,response,body){
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
});
});
});
And this is my client js where I fetch this exact same get with jQuery
$(document).ready(function() {
$.get('http://localhost:3000/', function(data) {
console.log(data);
$("#body").text(data);
});
});
When I open my index.html it displays the user interface correctly and inside my terminal where I have executing my server.js it correctly displays the url. What I can't accomplish is how to use my data that my jQuery receives in order to populate a table inside my html. My table will be populated with urls that are fetch from my endpoints.
I have some background in nodejs but I cant wrap this up.
Since you need to know when multiple requests are done, I'd suggest you switch to using the request-promise library so you can use promises to track when all the requests are done. That library also checks the statusCode for you automatically. So, you can do this:
const rp = require('request-promise');
app.get('/', function(req, res) {
Promise.all(endpoints.map(url => {
return rp(url).then(r => {
return url.url;
}).catch(err => {
// rather than error, just return null result
return null;
})
})).then(results => {
// filter out null values, then send array as the response
res.json(results.filter(item => item !== null));
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
This will run all the requests in parallel, but collect the results in order which should result in the fastest overall run time.
If you wanted to run them one a time, you could use async/await like this:
const rp = require('request-promise');
app.get('/', async function(req, res) {
let results = [];
for (let url of endpoints) {
try {
let r = await rp(url);
if (r) {
results.push(url.url);
}
} catch(e) {
// ignore error
}
}
res.json(results);
});
EDIT Jan, 2020 - request() module in maintenance mode
FYI, the request module and its derivatives like request-promise are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got() myself and it's built from the beginning to use promises and is simple to use.
You must wait for all requests gets resolved to then send final_res array back to client. You can do this using async/await and Promise.all concepts. If you don't want to use these resources then you'll need to count and wait all request manually, using a counter to know when all requests has done, as below:
app.get('/', function(req, res) {
var url;
var final_res = [];
var respCounter = endpoints.length;
endpoints.forEach(function(url){
request(url, function(error,response,body){
respCounter--;
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
if(respCounter == 0) {
res.send(final_res);
}
});
});
});
I want to call to API, get json data and set it to resolvers Query in Graphql. So far I managed to working Graphql server and get call to API. This is my code so far
//resolvers.js
//var fetch = require('node-fetch');
var request = require("request");
var options = { method: 'GET',
url: 'http://mydomain.con/index.php/rest/V1/products/24-MB01',
headers:
{ 'postman-token': 'mytoken',
'cache-control': 'no-cache',
'content-type': 'application/json',
authorization: 'Bearer mytoken' } };
const links = request(options, function (error, response, body) {
if (error) throw new Error(error);
//body = json data
//console.log(body);
});
module.exports = {
Query: {
//set data to Query
allLinks: () => links,
},
};
I dont know how to set the body parameter which contain json data to Query. I have also same data on "http://localhost/src/apicall.php" but this is not working with node-fetch (or Im making mistakes). Api is from magento2.
You were close !
What you are doing right now is sending the links request right when your application starts. You don't want that ; you want to send the request when the allLinks field is requested in GraphQL.
So what you need is to have in the allLinks field a function making the request to your API, and returning the response.
If you return a Promise within the allLinks field, it will wait upon completion to use the returned value as an answer.
So, putting it all together:
...
const getAllLinks = () => {
return new Promise((resolve, reject) => {
request(options, function (error, response, body) {
if (error) reject(error);
else resolve(body);
});
});
};
module.exports = {
Query: {
//set data to Query
allLinks: getAllLinks,
},
};
I'm running this code using the request module for node.js
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (err, res, body) {
console.log("Sent data");
});
I have tried running the above code just using standard Node.JS libraries, to no avail. The callback function is never fired and the request doesn't go through. I don't know why.
I believe I've found the answer to my own problem. The issue seems to be that I'm not allocating any time in the Node.js event loop to allow the request to be executed.
Have a look at this question:
your code should look something like
var hsKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsForm = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
var hsHost = "https://docs.google.com/"
var url = hsHost + "forms/d/" + hsForm + "/formResponse"
var form = {
"entry.129401737": pointsAvg,
"entry.2000749128": hiddenNeurons,
"submit": "Submit",
"formkey": hsKey
};
request.post({
url: url,
form: form
}, function (response) {
response.setEncoding('utf8');
response.on('data', function(chunk){
//do something with chunk
});
});
The data event should get fired on receiving a response.
So if you read the docs for the request module at npm
request
.get('http://google.com/img.png')
.on('response', function(response) {
console.log(response.statusCode) // 200
console.log(response.headers['content-type']) // 'image/png'
});
There is a response event that should get fired.
I ran into this as well. I ended up creating a separate js file containing only the request, without the describe and it methods, and running it with 'mocha mynewbarebonesreq.js'. suddenly I could see that there was an exception being thrown and swallowed by mocha (with the standard reporter, spec).
I finally installed and enabled mocha_reporter which shows the exceptions
now it looks like this:
describe('CMSLogin', function () {
it('should log in as user ' + JSON.stringify(USER_PASS), function (done) {
request({
url: "http://cms.lund.multiq.com:3000/api/CMSUsers/login",
method: "POST",
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
},
json: false,
body: JSON.stringify(USER_PASS)
}, (err, res, body) => {
var parsedBody = JSON.parse(body);
this.token = parsedBody.id;
console.log(this.token)
assert.equal(USER_PASS.userId, parsedBody.userId);
assert.doesNotThrow(() => Date.parse(parsedBody.created));
if (err) { done.fail(err); }
done();
});
});
}