I've checked the other questions but none form an answer to mine. In other words: no answer works.
I've got two modules: app and logic. App passes a callback to logic, which logic then calls. However I get the error "cb is not a function". That's it, no more information.
This is the function in app.js that poses the callback:
app.get('/assignments/open/:student', function (request, response) {
var callback = function(mail, jobtitle) {
response.status(200).json(logic.getOpenAssignments(request.params.student));
}
logic.examine(request, callback);
});
This is the function in logic.js that calls the callback:
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
var req = http.get(options, function(res) {
res.on('data', function(chunk) {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
},
Any solutions? Thanks in advance!
Edit:
Following code doesn't work:
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
var req = http.get(options, res => {
res.on('data', chunk => {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
},
Following code also doesn't work, does this mean the scope is not the problem?
examine: function (request, cb) {
var options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
cb('hehe', 'hoho');
},
If you're using ES6, try to use arrow function to pass the scope to http.get's callback function:
var req = http.get(options, res => {
res.on('data', chunk => {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
Or you could also pass cb to your callback function :
var req = http.get(options, function(res, cb) {
res.on('data', function(chunk, cb) {
chunk = JSON.parse(chunk);
mail = chunk['mail'];
jobtitle = chunk["jobTitle"];
cb(mail, jobtitle);
})
});
Maybe the issue is, you are not waiting for data chunk to process. Try the following snippet. Added a way to convert http.get to promises(very common) and this avoids passing all the messy callbacks.
//put this somewhere inside where examine is located.
logic.httpGet = options => {
return new Promise((resolve, reject) => {
http.get(options, res => {
res.setEncoding('utf8');
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => resolve(body));
}).on('error', reject);
});
};
//convert your route like this
app.get('/assignments/open/:student', function (request, response) {
cont options = {
host: 'graph.microsoft.com',
path: '/v1.0/me',
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': request.get('Authorization')
}
};
return logic
.httpGet(options)
.then((data)=>{
const data =JSON.parse(data);
//i don't see where you use the processed data but do whatever you want below here
repsonse.status(200).json(logic.getOpenAssignments(request.params.student))
})
})
Related
I am learning to use http post and trying to wait for it to end using promise. But I can't get it to work, please help:
var http = require('http');
const auth = () => {
var post_data = JSON.stringify({
"username": "aaa",
"password": "bbb"
});
const options = {
host: 'http://1.1.1.1',
path: '/v1/authentication',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': post_data.length
}
};
const req = http.request(options, (res) => {
res.setEncoding('utf8');
var body = '';
res.on('data', d => {
body += chunk;
});
res.on('end', function() {
console.log("Response body", body);
});
});
req.on('error', error => {
console.error("error", error);
});
req.write(post_data)
req.end();
return Promise.resolve("!!");
};
exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
return auth().then((res)=>{
res.status(200).send(res);
});
};
Entry point is the hellWorld function. What should I do to wait for the http post to finish and get the response result using promise?
here i did some for get api call.
try {
const auth = () => {
return new Promise((resolve, reject) => {
const options = {
host: 'api.github.com',
path: '/orgs/nodejs',
port: 443,
method: 'GET',
headers: {
'User-Agent': 'request'
}
};
const req = https.request(options, (res) => {
res.setEncoding('utf8');
res.on('data', d => {
resolve(d)
});
});
req.on('error', error => {
console.error("error", error);
});
req.end();
})
};
const data = await auth()
console.log('should execute first', data)
console.log('should executed after http call')
} catch (e) {
console.log(e)
}
you can modify above code with your, just you have to wrap your http call inside Promises.
comment down if any its a solution, and mark as a solution
I need to use require('http') (I cannot use other libraries), and I am trying to figure out how I would chain multiple http.request() together?
In my example below, I am trying to create a household with 4 people, and each person will have a pet associated to them. I have 3 routes that will createFamily, createPerson, and createPet. I also have the method createHousehold() that will take the ID's from the response of each route, and pass it down the chain (family -> person -> pet). I am not sure how I would be chaining the response of each route, and passing down the ID.
const http = require('http');
createHousehold('Smith', 4); // Creates 'Smith' family with 4 people, and each member has one pet
// Not sure how to chain requests
function createHousehold(surname, numberOfPeople) {
createFamily(surname)
.then(familyId => {
for (let i = 0; i < numberOfPeople; i++) {
createPerson(familyId)
.then(personId => createPet(personId));
}
});
}
function createFamily(surName) {
const data = JSON.stringify({
config: { surName }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/family',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createFamily(): ', error.message));
request.write(data);
request.end();
return request;
}
function createPerson(familyId) {
const data = JSON.stringify({
config: { familyId }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/person',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createPerson(): ', error.message));
request.write(data);
request.end();
return request;
}
function createPet(personId) {
const data = JSON.stringify({
config: { personId }
});
const options = {
host: 'myProxyHost.com',
port: '8080',
path: '/v1/pet',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
return (response.on('end', () => JSON.parse(data).id));
});
request.on('error', error => console.log('ERROR - createPet(): ', error.message));
request.write(data);
request.end();
return request;
}
For example with a proxy server, you would pipe one request (readable) into another request (writable).
If you are just doing serial requests, I would just wrap them in a promise, or use the async library.
function createPet(personId) {
return new Promise((resolve,reject) => {
const data = JSON.stringify({
config: { personId }
});
const options = {
host: 'myHost.com',
port: '8080',
path: '/v1/pet',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const request = http.request(options, response => {
let data = '';
response.on('data', chunk => data += chunk);
response.once('end', () => resolve(data)); // ! resolve promise here
});
request.once('error', err => {
console.log('ERROR - createPet(): ', err.message || err);
reject(err); // ! if promise is not already resolved, then we can reject it here
});
request.write(data);
request.end();
});
}
and use it like so:
createHousehold(id)
.then(createFamily)
.then(createPerson)
.then(createPet);
if you want to do things in parallel, then use Promise.all()..or use the async library.
For seeding a database, I highly recommend async.autoInject, you will quickly see why:
https://caolan.github.io/async/v2/docs.html#autoInject
you can use it like so:
const seedDatabase = () => {
return async.autoInject({ // returns a promise
async createHouseHold(){
return somePromise();
},
async createFamily(createHouseHold){
return somePromise();
},
async createPerson(createFamily){
return somePromise();
},
async createPet(createPerson){
return somePromise();
}
});
}
I am finding way out to use async / await with https post. Please help me out. I have posted my https post code snippet below.how do I use async await with this.
const https = require('https')
const data = JSON.stringify({
todo: 'Buy the milk'
})
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}
const req = https.request(options, (res) => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', (d) => {
process.stdout.write(d)
})
})
req.on('error', (error) => {
console.error(error)
})
req.write(data)
req.end()
Basically, you can write a function which will return a Promise and then you can use async/await with that function. Please see below:
const https = require('https')
const data = JSON.stringify({
todo: 'Buy the milk'
});
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
},
};
async function doSomethingUseful() {
// return the response
return await doRequest(options, data);
}
/**
* Do a request with options provided.
*
* #param {Object} options
* #param {Object} data
* #return {Promise} a promise of request
*/
function doRequest(options, data) {
return new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
resolve(JSON.parse(responseBody));
});
});
req.on('error', (err) => {
reject(err);
});
req.write(data)
req.end();
});
}
I had this problem also, found this post, and used the solution from Rishikesh Darandale (here).
The await documentation states The await operator is used to wait for a Promise. Returning the promise from a function is not required. You can just create a promise and call await on it.
async function doPostToDoItem(myItem) {
const https = require('https')
const data = JSON.stringify({
todo: myItem
});
const options = {
hostname: 'flaviocopes.com',
port: 443,
path: '/todos',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
},
};
let p = new Promise((resolve, reject) => {
const req = https.request(options, (res) => {
res.setEncoding('utf8');
let responseBody = '';
res.on('data', (chunk) => {
responseBody += chunk;
});
res.on('end', () => {
resolve(JSON.parse(responseBody));
});
});
req.on('error', (err) => {
reject(err);
});
req.write(data)
req.end();
});
return await p;
}
You can use async-await with Promises only and Node's core https module does not have build in promise support. So you first have to convert it into the promise format and then you can use async-await with it.
https://www.npmjs.com/package/request-promise
This module has converted the core http module into promisified version. You can use this.
I have middleware (API calls, not part of a route) which I want to use in a callback response.
// MIDDLEWARE EXAMPLE
var postInvoice = function(req, res){
function request(callback) {
var path='/xxx?';
var data = querystring.stringify( {
'action' : 'xxx',
'appkey' : 'xxx'',
'fromapi' : 'xxx',
'fromapiuser' : 'xxx',
'username' : 'xxx',
'shipmethod' : 'TEST',
'shipping' : '0',
'taxes' : '0'
});
var options = {
port: 443,
host: xxx,
path: path,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': data.length
}
};
var postRequest = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
console.log('Invoice Response: ' + chunk);
});
});
postRequest.write(data);
}
request(function(responseData) {
console.log(responseData);
});
}
I need to access the response in another route (which itself includes callback via API)
app.get('/result', function(req, res){
var resourcePath = req.param('resourcePath');
function request(callback) {
var path = resourcePath
var options = {
port: 443,
host: xxx,
path: path,
method: 'GET'
};
var postRequest = http.request(options, function(res) {
res.setEncoding('utf8');
res.on('data', function (chunk) {
jsonRes = JSON.parse(chunk);
return callback(jsonRes);
});
});
postRequest.end();
}
request(function(responseData) {
console.log(responseData);
// this is where I invoke the middleware,
if(some response condition is met) {
postinvoice();
}
res.render('result', {
check: check,
response: checkout_msg
});
});
});
I'm able to view the 'Invoice Response' in console, but I cannot manipulate it in the /result route. I'd like to be able to invoke the middleware, create locals and make the locals available in /result route.
thank you,
try this
var postRequest = http.request(options, function (response) {
var body = '';
response.setEncoding('utf8');
response.on('data', function (chunk) {
body += chunk;
});
response.on('end', function () {
body = JSON.parse(body); //if response is json
return callback(body);
});
});
I have working code to buffer a .json file and then POST that data to a server.
fs.readFile(filePath, 'utf-8', function (err, buf) {
if(err){
reject(err);
}
else{
const req = http.request({
method: 'POST',
host: 'localhost',
path: '/event',
port: '4031',
headers: {
'Content-Type': 'application/json',
'Content-Length': buf.length
}
});
req.on('error', reject);
var data = '';
req.on('response', function (res) {
res.setEncoding('utf8');
res.on('data', function ($data) {
data += $data
});
res.on('end', function () {
data = JSON.parse(data);
console.log('data from SC:', data);
//call fn on data and if it passes we are good
resolve();
});
});
// write data to request body
req.write(buf);
req.end();
}
});
what I would like to do instead is to avoid buffering it, and just use fs.createReadStream, something like so:
fs.createReadStream(filePath, 'utf-8', function (err, strm) {
if(err){
reject(err);
}
else{
const req = http.request({
method: 'POST',
host: 'localhost',
path: '/event',
port: '4031',
headers: {
'Content-Type': 'application/json',
// 'Content-Length': buf.length
}
});
req.on('error', reject);
var data = '';
req.on('response', function (res) {
res.setEncoding('utf8');
res.on('data', function ($data) {
data += $data
});
res.on('end', function () {
data = JSON.parse(data);
console.log('data from SC:', data);
//call fn on data and if it passes we are good
resolve();
});
});
// write data to request body
req.write(strm);
req.end();
}
});
but that doesn't quite work? Is it possible to do this?
This seems to work, but not sure if it's 100% correct
const strm = fs.createReadStream(filePath);
const req = http.request({
method: 'POST',
host: 'localhost',
path: '/event',
port: '4031',
headers: {
'Content-Type': 'application/json',
}
});
req.on('error', reject);
var data = '';
req.on('response', function (res) {
res.setEncoding('utf8');
res.on('data', function ($data) {
data += $data
});
res.on('end', function () {
data = JSON.parse(data);
resolve();
});
});
// write data to request body
strm.pipe(req);