I try to fetch data from different HTTP sources but I wasn't able to handle the asynchronous mode even with async...
var express = require('express');
var app = express();
var https = require("https");
var timer = require("./my_modules/timer/timer.js");
var http = require('http');
var bodyParser = require('body-parser');
var async = require('async');
var request = require('request');
//These are my source from API.
//Output is a Json file
var sources = {
cnn: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
bbc: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
guardian: 'https://newsapi.org/v1/articles?source=cnn&sortBy?&apiKey=c6b3fe2e86d54cae8dcb10dc77d5c5fc',
othersource: "otherurls..."
};
//I want to push the JSON object in this array
var resultArray = [];
//I setup a https GET request
var getJson = function(url) {
https.get(url, (res) => {
var body = '';
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
result = JSON.parse(body);
//push isn't working...
resultArray.push(result);
});
}).on('error', function(e) {
console.log('Got an error', e);
});
}
app.set('port', (process.env.PORT || 5000));
app.listen(
app.get('port'), () => {
console.log('We are live on port: ', app.get('port'));
getJson(sources.cnn);
});
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser.json());
app.use(function(req, res, next) {
res.setHeader('Content-Type', 'text/plain');
res.status(404).send('Page not found !');
res.status(503).send('Page not found, error 503');
});
console.log("resultArray:" + resultArray);
//resultArray = empty...
What should I do to push the result into my Array?
I couldn't find a way to set up a working callback function to push results into the Array.
Since you're already using the request package, have you tried something as simple as:
request({
url: sources.cnn,
json: true
}, function(error, response, body) {
var articles = body.articles;
// or by case, depending on what you want
// resultArray = resultArray.concat(articles);
resultArray.push({
cnn: articles
});
console.log(resultArray);
});
instead of writing your own getJson function?
Thanks Roby, your request is much clearer !
I have carefully read this really clear and helpful article : https://github.com/maxogden/art-of-node#callbacks
I think I got the logic :
//main function
function getJson(url, callback){
request({
url: url,
json: true,
callback:callback //added this
}, function(error, response, body) {
var articles = body.articles;
callback(articles);
});
}
//this callback function will be passed to the main function as the 2nd parameter
//it's possible to access "resultArray" ONLY from this function
var result = function(e){
resultArray.push(e);
console.log(resultArray);
};
//url and callback are passed as parameter
getJson(sources.cnn, result);
Thanks for the help
Related
I'm pretty new to javascript but I have a REST API I'm running on a LAN network. I have a MySQL database I'm trying to save a HTTP POST body to in JSON format. My js code will print the data as "result" for me but will not save it when it is sent from Postman, however if I hard code a fake entry into it as "var result = {JSON format entries}" it will then be able to be saved to MySQL. Here is my code:
var http = require('http');
var express = require('express');
var bodyParser = require('body-parser');
const { parse } = require('querystring');
var mysql = require("mysql");
var app = express();
var port = process.env.port || 8080;
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : '*******',
database : 'userInfo'
});
connection.connect(function(err) {
if (err) throw err
console.log('You are now connected with mysql database...')
})
app.post('/licence', function (req, res) {
collectRequestData(req, result => {
console.log(result);
connection.query('INSERT INTO licence SET ?',result, function (error,
results, fields) {
if (error) throw error;
res.end(JSON.stringify(results));
});
res.end(`Parsed data belonging to ${result.fname}`);
});
});
function collectRequestData(request, callback) {
const FORM_URLENCODED = 'application/json';
if(request.headers['content-type'] === FORM_URLENCODED) {
let body = '';
request.on('data', chunk => {
body += chunk.toString();
});
request.on('end', () => {
callback(parse(body));
});
}
else {
callback(null);
}
}
I'm pretty sure I don't need this line "res.end(Parsed data belonging to ${result.fname});" but what I am trying to figure out here is how to save result to the licence table in mysql. This is what console.log(result) prints: { '{"hash":"TestHaaaash", "size":13, "difficulty":47, "time":null, "timestamp":null, "date":null}': '' } I think this should be slightly different but I'm not sure how it should be or how to change it
In collectRequestData try chaging
request.on('end', () => {
callback(parse(body));
});
to
request.on('end', () => {
callback(JSON.parse(body));
});
I am trying to make a POST request with a JSON payload to an external API using node.
Here is my code:
var express = require('express');
var bodyParser = require('body-parser');
var cors = require('cors');
var url = require("url");
var http = require("http");
var app = express();
app.use(cors());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/api', function(req, res) {
var query = url.parse(req.url, true).query;
var key = query.key;
console.log('JSON PAYLOAD:');
console.log(req.body); **//PAYLOAD COMES THROUGH AS EXPECTED**
var options = {};
options = {
host: 'localhost',
port: 1234,
method: 'POST',
headers: {'Content-Type': 'application/json'},
path: '/api?key=1234'
};
var request = http.request(options, function(response) {
response.setEncoding('utf-8');
var responseString = '';
response.on('data', function(data) {
responseString += data;
});
response.on('end', function() {
var resultObject = JSON.parse(responseString);
res.json(resultObject);
});
});
request.on('error', function(e) {
});
request.write(req.body) **//THIS METHOD SHOULD BE FORWARDING THE PAYLOAD BUT THIS IS NOT THE CASE...**
request.end();
});
The JSON payload comes through as expected from the origin. However I am unable to forward this payload to the external API. 'request.write(req.body)' appears to be the way to do this, however the external API is still receiving a null payload.
Any help would be appreciated. Thanks.
Try this Inside the app.post block
var options = {
host: 'localhost',
path: '/api?key=1234',
port: 1234,
method: 'POST',
headers: {'Content-Type': 'application/json'}
};
callback = function(response) {
var str = ''
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
console.log(str);
});
}
var req = http.request(options, callback);
req.write(JSON.stringify(req.body));
req.end();
New to node and trying not to do any callback hell.
I have two files
routes.js
fetch.js
//routes.js
var fetchController = require("../lib/mtl_fetcher/fetcher_controller");
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.send(fetchController.getAllTransgressor(function(results) {
return results.end();
}))
});
module.exports = router;
and
//fetch.js
var http = require('http');
var config = require('./config')
var Iconv = require('iconv').Iconv
module.exports.getAllTransgressor = function(callback) {
var req = http.get(config.urlOptions.host, function (response) {
var bufferChunk = [];
var str
if(response.statusCode == 200) {
response.on('data', function(chunk) {
bufferChunk.push(chunk);
})
response.on('end', function(callback) {
var iconv = Iconv('latin1', 'UTF-8');
str = iconv.convert(Buffer.concat(bufferChunk)).toString();
console.log(str)
});
} else {
console.log("handle this")
}
});
req.on("error", function(err) {
callback(err);
});
callback(req)
}
So the goal is to fetch and then show what has been fetch to the screen. The ressource is XML base.
Doing all of this in one block (routes.js) works, but when I try to refactor and set up some modularity my str just shows in shell stdout.
Using req.end() does not send the content back.
Firstly, you need to send inside the callback, where the result is actually available, as you can't return from an asynchronous function
router.get('/', function(req, res, next) {
fetchController.getAllTransgressor(function(error, results) {
if ( error ) {
// handle errors
} else {
res.send(results);
}
});
});
The same goes for the callback function, it has to be called when the data is available, after the request and parsing
module.exports.getAllTransgressor = function(callback) {
var req = http.get(config.urlOptions.host, function(response) {
var bufferChunk = [];
if (response.statusCode == 200) {
response.on('data', function(chunk) {
bufferChunk.push(chunk);
});
response.on('end', function() {
var iconv = Iconv('latin1', 'UTF-8');
var str = iconv.convert(Buffer.concat(bufferChunk)).toString();
callback(null, str); // here, stuff is available
});
} else {
callback('Did not return 200', err);
}
});
req.on("error", function(err) {
callback(err, null);
});
}
I found 2 methods to get the Post Body data in Node.js
Below is the 2 webservice Post methods, so which is preferred approach that needs to be followed while fetching the data from client through rest api in Node.js or is there any other approach to read post data.
1st Method
//http://localhost:1337/api/postparams1
//Content-Type: application/x-www-form-urlencoded
//param1=complete+reference¶m2=abcd+1234
function postparams1(req, res)
{
var result =
{
Url : req.originalUrl,
Method : req.method,
Param1 : req.body.param1,
Param2 : req.body.param2
};
res.status(200).send(result);
}
2nd Method
//http://localhost:1337/api/postparams2
//{
// "param1" : "param value 1",
// "param2" : "param value 2"
//}
function postparams2(req, res)
{
var data = '';
req.setEncoding('utf8');
req.on('data', function (chunk) {
data += chunk;
console.log("In data : " + data);
});
req.on('end', function () {
console.log("In end : " + data);
var newObj = JSON.parse(data);
newObj.Url = req.originalUrl;
newObj.Method = req.method,
res.status(200).send(newObj);
});
}
I think first option is more common beacause needs less code but you need to use Express.
Express 3 code:
app.use(express.bodyParser());
app.post('/', function(request, response){
console.log(request.body.param1);
console.log(request.body.param2);
});
Express 4 code:
var bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.post('/', function(request, response){
console.log(request.body.param1);
console.log(request.body.param2);
});
See more info here:
Extract post data in node
var req = https.get("url", function(response) {
var str = ''
response.on('data', function (chunk) {
str += chunk;
});
response.on('end', function () {
console.log(str);
});
});
req.end();
req.on('error', function(e) {
console.error(e);
});
I have a route I that in order to get all the data needs to access the API server multiple times (according to the data that was given).
Now I need to add a third access to the server and it's getting rather unreadable.
The following code is working, but I have a feeling I'm not doing it right (promises?) - couldn't figure out what exactly is recommended in this case
The code: (stripped down to emphasise the point)
router.get('/', function(req, main_response) {
http.get(FIRST_API_COMMAND, function (res) {
var moment_respose_content = '';
res.on("data", function (chunk) {
moment_respose_content += chunk;
});
res.on('end',function(){
if (res.statusCode < 200 || res.statusCode > 299) {
main_response.send('error in getting moment');
return;
}
var response = JSON.parse(moment_respose_content );
if (response.success)
{
var data = response.data;
//doing something with the data
http.get(SECOND_API_COMMAND, function (res) {
res.on("data", function (chunk) {
comment_respose_content += chunk;
});
res.on('end',function(){
var response = JSON.parse(comment_respose_content);
if (response.success)
{
var comments = response.data;
main_response.render('the page', {data: data});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting comments');
});
return;
}
});
}).on('error', function (e) {
console.log("Got error: " + e.message);
main_response.send('Error in getting moment');
});
});
You can write a middleware for each remote action, and then use those middlewares before the get handler, so the get handler can simply access their results. (Promises can help if you need to start subsequent requests before waiting for earlier ones to finish, but that situation is rare.)
For example, using express middleware to fetch each remote data independently:
var request = require('request');
var express = require('express');
var app = express();
var router = express.Router();
/* middleware to fetch moment. will only run for requests that `router` handles. */
router.use(function(req, res, next){
var api_url = 'https://google.com/';
request.get(api_url, function(err, response, body) {
if (err) {
return next(err);
}
req.moment_response = response.headers["date"];
next();
});
});
/* middleware to fetch comment after moment has been fetched */
router.use(function(req, res, next){
var api_url = 'https://www.random.org/integers/?num=1&min=1&max=100&col=1&base=10&format=plain&rnd=new';
request.get(api_url, function(err, response, body){
if (err) {
return next(err);
}
req.comment_response = parseInt(body);
next();
});
});
/* main get handler: expects data to already be loaded */
router.get('/', function(req, res){
res.json({
moment: req.moment_response,
comment: req.comment_response
});
});
/* error handler: will run if any middleware called next() with an argument */
router.use(function(error, req, res, next){
res.status(500);
res.send("Error: " + error.toString());
});
app.use('/endpoint', router);
app.listen(8000);
Often the remote data you want to fetch is based on some parameter of the main request. In this case you would want to use req.param() instead of App.use() to define the data-loading middleware.