I am having a simple http server that returns a message based on the message returned from another request.
const http = require('http');
const app = new http.Server();
var message = 'm1';
const options = {
method: 'GET',
hostname: '<some-hostname>',
port: <some_port>
};
app.on('request', (rq, rs) => {
const m2req = http.request(options, (res) => {
res.on('data', (d) => {
message = d;
process.stdout.write(message);//this prints m2, which is correct
})
})
m2req.on('error', (error) => {
console.error(error)
})
m2req.end();
rs.writeHead(200, { 'Content-Type': 'text/plain' });
rs.write(message);// this should print 'm2' but prints 'm1'
rs.end('\n');
});
app.listen(<some_port>, () => {
});
What is the right way so my server prints m2 instead of m1?
Thank you for your time.
Nodejs is asynchronous, you have to use like this below
app.on('request', (rq, rs) => {
const m2req = http.request(options, (res) => {
var data = []
res.on("data", (d) => { data.push(d) })
res.on('end', () => {
rs.writeHead(200, { 'Content-Type': 'text/plain' });
rs.write(Buffer.concat(data).toString());// this should print 'm2' but prints 'm1'
rs.end('\n');
})
})
m2req.on('error', (error) => {
console.error(error)
})
m2req.end();
});
In your code, you are requesting another service, which is an asynchronous operation. so the variable message is still "m1", because before the service returns the value your res.write(message) executes so it's still "m1". You should write res.send() res.write() res.writeHead inside the callback of res.on
const http = require('http');
const app = new http.Server();
var message = 'm1';
const options = {
method: 'GET',
hostname: '<some-hostname>',
port: <some_port>
};
app.on('request', (rq, rs) => {
const m2req = http.request(options, (res) => {
res.on('data', (d) => {
message = d;
process.stdout.write(message);//this prints m2, which is correct
rs.writeHead(200, { 'Content-Type': 'text/plain' });
rs.write(message);// this should print 'm2' but prints 'm1'
rs.end('\n');
})
})
m2req.on('error', (error) => {
console.error(error)
})
m2req.end();
});
app.listen(<some_port>, () => {
});
Related
The data I am receiving through the code is outputting to the cmd through console.log but I can't seem to figure out how to make that same data available for GET requests from postman. Thank you
const express = require('express');
const app = express();
const PORT = 5000;
const apicall = require('./apicall');
const request = require('request');
app.get('/', (req, res) => {
res.send("Hello world!")
});
app.get('/getinfo', (req, res, body) => {
const getToken = (url, callback) => {
const options = {
url: process.env.GET_TOKEN,
json: true,
body: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
grant_type: 'client_credentials'
}
};
request.post(options, (err, res, body) => {
if(err) {
return console.log(err)
}
console.log(`Status: ${res.statusCode}`)
console.log(body);
callback(res);
});
}
var AT = '';
var info = '';
getToken(process.env.GET_TOKEN, (res) => {
AT = res.body.access_token;
return AT;
});
const getGames = (url, accessToken, callback) => {
const gameOptions = {
url: process.env.GET_GAMES,
method: 'GET',
headers: {
'Client-ID': process.env.CLIENT_ID,
'Authorization': 'Bearer ' + accessToken
}
};
request.get(gameOptions, (err, res, body) => {
if(err) {
return console.log(err);
}
let x = '';
console.log(`Status: ${res.statusCode}`);
console.log(JSON.parse(body));
//res.send(parsed);
//req.body.getinfo = JSON.parse(body);
})
}
setTimeout(() => {
getGames(process.env.GET_GAMES, AT, (response) => {
});
}, 1000);
//res.send(JSON.parse(body));
});
app.listen(PORT, () => {
console.log(`Example app listening on port ${PORT}`);
});
You use res.send in the callback of a request.get. But in that context, res is the incoming response from the API that you call, not the outgoing response created by your app. Only the outgoing response contains a send method.
To keep both separate, use different names:
app.get("/getinfo", function(req, res) {
request.get(..., function(err, incoming_res, body) {
res.json(JSON.parse(body));
});
});
res.send is a part of express. If the res.send that's failing is in request.get then that's because it's not a part of express.
From the docs for request it says that the response argument will be an instance of http.IncomingMessage. That should mean you can simply use res.end
Edit:
#HeikoTheißen is right. There is no res.end.
But this could be handled in a different way. If we can wrap the get request inside a promise, then we could resolve the promise with whatever needs to be sent from the get request.
An example:
const result = await new Promise((resolve) => {
request(gameOptions, function (error, response, body) {
resolve ({status : 'A Ok!'}) // <--- send response here
}
}
console.log ("result is ", result) // <-- Object {status : 'A Ok!'}
You just pipe it to the response like so .pipe(res)
const express = require('express');
const app = express();
const PORT = 5000;
const apicall = require('./apicall');
const request = require('request');
app.get('/', (req, res) => {
res.send("Hello world!")
});
app.get('/ne2', (req, res) => {
//res.send('This is the new endpoint');
apicall.getCall;
});
app.get('/getinfo', (req, res, body) => {
const getToken = (url, callback) => {
const options = {
url: process.env.GET_TOKEN,
json: true,
body: {
client_id: process.env.CLIENT_ID,
client_secret: process.env.CLIENT_SECRET,
grant_type: 'client_credentials'
}
};
request.post(options, (err, res, body) => {
if(err) {
return console.log(err)
}
console.log(`Status: ${res.statusCode}`)
console.log(body);
callback(res);
});
}
var AT = '';
var info = '';
getToken(process.env.GET_TOKEN, (res) => {
AT = res.body.access_token;
return AT;
});
const getGames = (url, accessToken, callback) => {
const gameOptions = {
url: process.env.GET_GAMES,
method: 'GET',
headers: {
'Client-ID': process.env.CLIENT_ID,
'Authorization': 'Bearer ' + accessToken
}
};
request.get(gameOptions, (err, res, body) => {
if(err) {
return console.log(err);
}
let x = '';
console.log(`Status: ${res.statusCode}`);
//console.log(JSON.parse(body));
info = JSON.parse(body);
console.log(info);
//res.send(parsed);
//req.body.getinfo = JSON.parse(body);
}).pipe(res);
}
setTimeout(() => {
getGames(process.env.GET_GAMES, AT, (response) => {
});
}, 1000);
//res.send(info);
});
app.listen(PORT, () => {
console.log(`Example app listening on port ${PORT}`);
});
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'd want to use the d variable outside the res.on function but it doesn't see it.
In other words, how can I access the result I get from my GET request. (I want to send it to the client side)
Currently I can just log it with the process.stdout.write(d) line. Anywhere outside res.on it doesn't work (even if I declare it outside). Thank you.
let data;
app.post("/api/route", function(req, res) {
var options = {
host : 'api.track-pod.com',
port : 443,
path : '/Route/Code/R000409',
method : 'GET',
headers: {
'Content-Type': 'application/json',
'X-API-KEY': 'xxx'//req.body.value.key
}
};
req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
//process.stdout.write(d)
data =+d;
})
})
req.on('error', error => {
console.error(error)
})
res.on("end", d => {
// Now all the data is stored in the data variable
processData(data);
});
function processData(data) {
return data;
}
res.send({"data":processData(data)})
});
You can use promises to do that:
const https = require('https')
const options = {
hostname: 'encrypted.google.com',
port: 443,
path: '/',
method: 'GET'
};
const req = () => {
return new Promise((response, reject) => {
let result = https.request(options, res => {
console.log('in here');
console.log(`statusCode: ${res.statusCode}`);
let data;
res.on('data', d => {
data += d;
// process.stdout.write(d)
})
res.on('error', error => {
console.error(error);
reject(error);
})
res.on("end", d => {
response(data);
});
})
result.end();
})
}
req().then(data => { console.log(data)}).catch(console.log);
You need to use the "end" event. Declare a data variable outside of the request body and process the data when all the data is downloaded.
let data;
function processData(data) {
// process the data here
}
const req = https.request(options, res => {
console.log(`statusCode: ${res.statusCode}`)
res.on('data', d => {
data += d;
})
res.on("end", d => {
// Now all the data is stored in the data variable
processData(data);
});
})
Another way would be piping the res into a writable stream because the res is a readable stream.
res.pipe(any_writable_stream_here);
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'm trying to do a HTTPS request in nodejs as follows:
var makeRequest = options => {
const req = https.request(options, res => {
// console.log('statusCode:', res.statusCode);
// console.log('headers:', res.headers);
res.on('data', d => {
process.stdout.write(d);
});
});
req.on('error', e => {
console.error(e);
});
req.end();
// return results;
};
Instead of print it i would like to return this value to another function, that should looks like:
{items:[..,..,...]}
one way would be writing the function with the callback, where the function send the request ,as the response we will getting would be stream we would have store in the temporary variable, and after successfully getting the whole response, will have to pass the response to the callback function.
const https = require('https');
const StringDecoder = require('string_decoder').StringDecoder;
const options = {
hostname: 'encrypted.google.com',
port: 443,
path: '/',
method: 'GET'
};
function getData(callbackfun){
const req = https.request(options, (res) => {
const decoder = new StringDecoder('utf-8');
let responseData = '';
res.on('data', (data) => {
responseData += decoder.write(data);
});
res.on('end',function(){
responseData += decoder.end();
callbackfun(responseData)
})
});
req.on('error', (e) => {
callbackfun(e)
});
req.end()
}
getData((result)=>{
console.log(result);
})