I'm using Node.JS with Express (and ejs for the views) and I want to call two API endpoints to render them in the same page and use the data. I've tried doing it with async but I get
ECONNRESET: Request could not be proxied!
This is my code
app.get('/profile', function(req, res) {
async.parallel([
function(next) {
var query = req.query.search;
var url = '1st url' + query;
var request = require('request');
request(url, function(error, body) {
var data = JSON.parse(body);
next(error, data);
});
},
function(next) {
request('2nd url', function(error, tlist) {
var list = JSON.parse(tlist);
next(error, list);
});
}], function(err, results) {
if (!err && results.statusCode == 200)
var data = results[0];
var list = results[1];
res.render('profile', {data: data, list: list});
});
});
Unsure about Cloud9, but if the issue is around parsing data, there's a couple of things here.
You should handle the error on each request before you attempt to parse; if parse throws an exception, your callback won't be executed:
request(url, function(error, body) {
if (error) return next(error);
var data = JSON.parse(body);
next(null, data);
});
You should probably also have a try/catch around the parse, and execute your callback with an error if there's an exception:
request(url, function(error, body) {
if (error) return next(error);
var data;
try {
data = JSON.parse(body);
} catch (e) {
return next(new Error('Unable to parse body for ' + url));
}
next(null, data);
});
Finally, your current check for results.statusCode will always return false, since it's an array, so you won't reach the end of the request. I'm guessing this is probably where the problem lies. I would also recommend passing any errors from async on to the Express error handler:
function(err, results) {
if (err) {
// pass to Express error handler...
}
var data = results[0];
var list = results[1];
res.render('profile', {data: data, list: list});
});
Related
Controller code:
bina: function(req, res) {
var request = require('request');
request({
url: 'http://localhost:3000/bina/',
method: 'GET',
}, function(err, res, body) {
if (err) {
console.log(err);
} else {
var data = JSON.parse(res.body);
console.log(data);
res.render(data)
}
})
}
The data that comes with the request does not see any functions like res.view or res.render.
Error output:
res.render(data)
^
TypeError: res.render is not a function
Note:
I can see the data via console.log(data) via web service. I use Sail.js.
Here's what you are doing wrong:
You are using same variable (res) name twice. And at the res.render it taking the one which is in the nearest scope. I have renamed the res => to response and now it should work.
bina: function(req, res) {
var request = require('request');
request({
url: 'http://localhost:3000/bina/',
method: 'GET',
}, function (err, response, body) { // Changed the variable name
if (err) {
console.log(err);
}
else {
var data = JSON.parse(response.body);
console.log(data);
res.render(data)
}
})
}
Hope it solved your issue.
I'm trying to get the results pulled from the API inserted into a database. It returns a SQL error when the program is run. It seems I'm not having this sent in the right syntax and I cant seem to to get it to do so. Is there a better way to do this?
var request = require('request');
var mysql = require('mysql');
var replace = require ('Regexp')
var url = 'https://api.nicehash.com/api?method=stats.provider.workers&addr=3Hwm6i8aefzHhJTbEGtSJeR6tZCJXqY7EN';
//connect to database
var con = mysql.createConnection({
host: 'localhost',
user: 'xxxxx',
password: 'xxxxx',
database: 'xxxxx',
table: 'workerstats'
});
con.connect(function(err) {
if (err) throw err;
console.log("Connected!");
});
const requestHandler = (request, response) => {
response.end(workerstats)
}
request.get({
url: url,
json: true,
headers: {'User-Agent': 'request'}
}, (err, res, data) => {
if (err) {
console.log('Error:', err);
}
else if (res.statusCode !== 200)
{
console.log('Status:', res.statusCode);
}
else {(!err && data && data.result && data.result.workers)
var workerstats = JSON.stringify(data.result.workers);
var wsclean = workerstats.replace(/[&\/\\#+()$~%'*?<>{}]/g,'')
.replace(/"a":/g,'');
};
console.log(wsclean);
var sql = "INSERT INTO 'workerstats' (workers, accepted, uptime, xnsub, difficulty, zone, algo) ?", wsclean;
con.query(sql, [workerstats], function (err, result) {
if (err) throw err;
console.log("Number of records inserted: " + result.affectedRows);
}
);
})
EDIT: Okay so after hours of tinkering, I 'think' I've made progress, but that silly A: has got me again. Its viewing as an object, and SQL is rejecting it. Though I thought (Though obviously improperly) I converted it to string. This is the amended code. Please forgive the formatting, it wasnt playing nice.
request.get({
url: url,
json: true,
headers: { 'User-Agent': 'request' }
}, (err, res, data) => {
if (err) {
console.log('Error:', err);
}
else if (res.statusCode !== 200) {
console.log('Status:', res.statusCode);
}
else {
(!err && data && data.result)
var data = JSON.parse(data.result);
var responseJson = JSON.stringify(data.response);
var query = connection.query('INSERT INTO table SET column=?', responseJson, function (err, result) {
if (err) throw err;
console.log('data inserted');
});
}
});
It returns the following error:
undefined:1
[object Object]
SyntaxError: unexpected token o in JSON at postion 1
Awesome. So somewhere I did something stupid, or improperly. In the raw API that object Object appears like: {"a":"158.01"} - How do I convert that to a string, when I thought I already did? Id also like to eliminate the 'a' and the ':' entirely as im not sure how to process that into SQL and its unneeded information.
When you setup json: true in the request option, You no longer have to perform JSON.parse(data.result), you directly access the data as object. Therefore the error, because JSON.parse({ a: 1}) call the toString method, and the result [object Object] its not valid JSON.
Note: You convert the data.result.workers to a string. I think you should leave it as an array for it to work.
con.query(sql, data.result.workers, function (err, result)
I have partially written a NODE.JS file to update the JSON file with data received from the client. The post works successfully. The Get command does not. I was wondering if there's a better way to do this? I have about 6 different callback options to write for. All different. I was wondering if there's a node.JS script already done that has all of the things I need. Or if there's a different language that would make it easier.
Here's the NODE:
var http = require('http');
var fs = require('fs');
http.createServer(function (req, res) {
console.log('Request received: ');
if (req.method == 'POST') {
req.on('data', function (chunk) {
fs.writeFile("comments-data.json", chunk, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
})
});
res.end('{"msg": "success"}');
};
if (req.method == 'GET') {
req.on('data', function (chunk) {
fs.readFile('comments-data.json', 'utf8', function (err, data) {
if (err) throw err;
obj = JSON.parse(data);
return data;
});
});
res.end(data);
};
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
Here's the AJAX call:
postComment: function(commentJSON, success, error) {
$.ajax({
type: 'post',
url: 'http://127.0.0.1:8080',
data: commentJSON,
success: function(comment) {
success(comment)
},
error: error
});
},
But there's an ajax call for all sorts of things with the jquery plugin that i'm using. I need to GET, POST, PUT, DELETE, and sometimes multiple within the call.
Here's a full list of all of the callbacks i'm using:
http://viima.github.io/jquery-comments/#link-3-6
Using express you can do this much easily.
const express = require('express');
const app = express.Router();
//POST Request
app.post('/',(req, res, next)=>{
fs.writeFile("comments-data.json", chunk, function(err) {
if(err) {
return console.log(err);
}
console.log("The file was saved!");
res.json({'status': 'Success'})
})
})
//GET Request
app.get('/',(req, res, next)=>{
fs.readFile('comments-data.json', 'utf8', function (err, data) {
if (err) throw err;
obj = JSON.parse(data);
res.json({'status': 'Success', 'data':data})
});
})
As for your question regarding writing it in a different module. That is based on the pattern adopted by you. There are various nodejs patterns available eg. Controller based or classes based. It all depends on what you find comfortable.
Having a strange problem. Been searching for answers but nothing turns up. I'm doing a node api tutorial and it returns JSON from my mongoDB database in my terminal when I perform any GET request but in my browser or postman I get nothing back, only in the terminal do I get any response. When I try a POST in postman it says it can't connect to the backend.
here is my code :
var http = require('http');
var url = require('url');
var database = require('./database');
// Generic find methods (GET)
function findAllResources(resourceName, req, res) {
database.find('OrderBase', resourceName, {}, function (err, resources) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resources));
});
};
var findResourceById = function (resourceName, id, req, res) {
database.find('OrderBase', resourceName, {'_id': id}, function (err, resource) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resource));
});
};
// Product methods
var findAllProducts = function (req, res) {
findAllResources('Products', req, res);
};
var findProductById = function (id, req, res) {
findResourceById('Products', id, req, res);
};
// Generic insert/update methods (POST, PUT)
var insertResource = function (resourceName, resource, req, res) {
database.insert('OrderBase', resourceName, resource, function (err, resource) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resource));
});
};
// Product methods
var insertProduct = function (product, req, res) {
insertResource('OrderBase', 'Product', product, function (err, result) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(result));
});
};
var server = http.createServer(function (req, res) {
// Break down the incoming URL into its components
var parsedURL = url.parse(req.url, true);
// determine a response based on the URL
switch (parsedURL.pathname) {
case '/api/products':
if (req.method === 'GET') {
// Find and return the product with the given id
if (parsedURL.query.id) {
findProductById(id, req, res)
}
// There is no id specified, return all products
else {
findAllProducts(req, res);
}
}
else if (req.method === 'POST') {
//Extract the data stored in the POST body
var body = '';
req.on('data', function (dataChunk) {
body += dataChunk;
});
req.on('end', function () {
// Done pulling data from the POST body.
// Turn it into JSON and proceed to store it in the database.
var postJSON = JSON.parse(body);
insertProduct(postJSON, req, res);
});
}
break;
default:
res.end('You shall not pass!');
}
});
server.listen(8080);
console.log('Up and running, ready for action!');
You have several callbacks with err as first argument but you are not treating any potential error. It means if something is going wrong, you are not catching it and returning an error. I don't know if this has anything to do with it, but as a practice (not even "best", but general practice) instead of doing this
function (err, resource) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resource));
}
do this
function (err, resource) {
if(err){
// do something to warn the client and stop here
}
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resource));
}
Try that, see if you are actually running into errors before trying to output an answer.
https://nodejs.org/api/http.html#http_response_end_data_encoding_callback
The response end method not send data to response socket. Maybe you change it
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(resource));
res.writeHead(200, {'Content-Type': 'application/json'});
res.write(JSON.stringify(resource));
res.end();
if you want socket to close to do something, you can into callback to end.
res.end(#logHandle());
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var connect = function (databaseName, callback) {
var url = 'mongodb://localhost:27017/' + databaseName;
MongoClient.connect(url, function (error, database) {
assert.equal(null, error);
console.log("Successfully connected to MongoDB instance!");
callback(database);
})
};
exports.find = function (databaseName, collectioName, query, callback) {
connect(databaseName, function (database) {
var collection = database.collection(collectioName);
collection.find(query).toArray(
function (err, documents) {
assert.equal(err, null);
console.log('MongoDB returned the following documents:');
console.dir(JSON.parse(JSON.stringify(documents)));
//console.dir(documents);
callback(null, documents);
}
)
database.close();
})
};
I think we are going through the same tutorial, this is my solution of 'database.js', works for me.
One of my controller is doing a crawl of 100s of pages wherein its extracting all the links from the page and when the links after saved to the database, i'm using a afterCreate lifecycle callback (below is the code)
afterCreate: function(createdLink, next) {
var request = require("request");
var currentLink = config.apiUrl + "update/linkstatus?linkPath=" + createdLink.linkUrl;
request(currentLink, function(error, response, body) {
console.log("saved", body);
});
next();
}
this triggers another controller which gets the status of each of those links; below is the code for this controller:
linkstatus: function(req, res) {
var request = require("request");
var currentLink = req.query.linkPath;
request(currentLink, function(error, response, body) {
if(error) {
console.log(error);
}
var thisStatusCode = response.statusCode;
Link.update(
{linkUrl: currentLink}, {statusCode: thisStatusCode}
).exec(function(err, updatedLink) {
res.status(200).send(updatedLink);
});
});
}
The issue is that after some calls, I start getting the following error:
TypeError: Cannot read property 'statusCode' of undefined
at Request._callback (/home/ubuntu/myapp/api/controllers/UpdateController.js:11
2:32)
at self.callback (/home/ubuntu/myapp/node_modules/request/request.js:360:22)
at Request.emit (events.js:107:17)
at Request.onRequestError (/home/ubuntu/myapp/node_modules/request/request.js:1
Assuming that the 'linkstatus' controller action that I've written is not done properly to handle getting status code responses from 1000s of links simultaneously and as per my understanding, I need to use async module and Promises to solve this but i'm having difficulty grabbing the concept of callback and Promises so would be fantastic to get input on this
Your issue is that your not guaranteed a response and in those cases where the requests fails inside of node you to check for that before moving forward.
linkstatus: function(req, res, next) {
var request = require("request");
var currentLink = req.query.linkPath;
request(currentLink, function(error, response, body) {
if(error || !response) {
console.log(error);
}
else {
var thisStatusCode = response.statusCode;
Link.update(
{linkUrl: currentLink}, {statusCode: thisStatusCode}
).exec(function(err, updatedLink) {
res.status(200).send(updatedLink);
});
}
});
}