NodeJS : app.get() does not operate as I exected - javascript

I am new to NodeJS and here is my routes/recom.js which is now doing a lot of logics stuffs. I will move the logics to somewhere else later. But now I need to solve the error first.
exports.scrape = function(req, res) {
var APIURI = 'https://www.kimonolabs.com/api/abbxqyg4?apikey=6IrCGNcorodTBSfNawS6sZkHw3LeZVIN';
var receivedJason;
res.type('text/plain');
request({
url: APIURI,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
console.log('API Retrieved Successfully!');
res.json(body);
receivedJason = JSON.stringify(body);
var node = db.createNode({hello: 'world'}); // instantaneous, but...
node.save(function (err, node) { // ...this is what actually persists.
if (err) {
console.error('Error saving new node to database:', err);
} else {
console.log('Node saved to database with id:', node.id);
}
});
}
});
};
And this is my app.js
var express = require('express');
var recom = require('./server/routes/recom.js');
var app = express();
app.get('/', recom.scrape);
app.listen(process.env.PORT || 2019);
and I got the following error:
Route.get() requires callback functions but got a [object Undefined]
any help would be appreciated.

The error seems to be in the export. In routes/recom.js use:
module.exports.scrape = function(req, res) { //...
The reason you get an [object Undefined] is that exports is not the same object as module.exports, and thus the item looked for does not exist.
In addition, in app.js you may need to use one of:
var recom = require('routes/recom.js');
// or:
var recom = require('server/routes/recom.js');
Depending on you full structure.

Related

Having difficulty returning a value from an async function

I'm new to Node and have previously just written Javascript for simple browser extensions. What I'm trying to do is run a shell script and then return the text for it on a get request (simplified version).
I've tried looking at callbacks and can't seem to get my head around it or even adapt another example to what I'm trying to do. My main problem is either that the I'm receiving the error "first argument must be one of type string or buffer. received type undefined" or "received type function" (when I tried to implement a callback, which is what I believe I need to do here?).
I've looked at a few examples of callbacks and promises and seeing them in abstraction (or other contexts) just isn't making sense to me so was hoping someone could help direct me in the right direction?
The code is very crude, but just trying to get some basic functionality before expanding it any further.
var express = require("express");
var app = express();
const { exec } = require("child_process");
var ifcfg = function(callback) {
exec("ifconfig", (error, stdout, stderr) => {
if (error) {
console.log(`error: ${error.message}`);
return error;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return err;
} else {
var output = stdout.toString();
return callback(output);
}
});
}
app.get("/ifconfig", (req, res) => res.write(ifcfg(data)));
var port = process.env.PORT || 8080;
app.listen(port, function() {
console.log("Listening on " + port);
});
In JavaScript, a callback is a function passed into another function as an argument to be executed later.
Since the command is executed asynchronously you will want to use a callback to handle the return value once the command has finished executing:
var express = require("express");
var app = express();
const { exec } = require("child_process");
function os_func() {
this.execCommand = function(cmd, callback) {
exec(cmd, (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
callback(stdout);
});
}
}
app.get("/", (req, res) => {
console.log("InsideGetss");
var os = new os_func();
os.execCommand('ifconfig', function (returnvalue) {
res.end(returnvalue)
});
});

Express over Node.js - TypeError: Cannot read property 'forEach' of undefined

I'm building my first node/express app and am following this tut.
I am at a point where I am trying to get all JSON data and put it in an array to be sent to the template and rendered. When I try to run the app via CLI, I get the following error:
Directory Structure
The data output at the var blogsurlall location
hellotest.js
var routes = require('./routes/index');
var express = require('express');
var app = express();
var request = require("request");
var blogsurlall = "https://[JSON export URL location configured in a Drupal 8 view]";
app.set('view engine','ejs');
var server = app.listen (2000, function(){ console.log('Waiting for you on port 2000'); });
/* Get all global blogs data */
request({
url: blogsurlall,
json: true
}, function (error, response, body) {
if (!error && response.statusCode === 200) {
blogsdata_all = body;
}
// Create blogs array for footer.
var blogs = [];
// Fill up the array with blogs.
blogsdata_all.blogs.forEach(function(item){
blogs = blogs.concat(item);
});
app.locals.blogsdata = blogs;
});
app.use('/', routes);
index.js
var express = require('express');
var routes = express.Router();
routes.get('/', function(req, res){ res.render('default',{title: 'Home', body: 'blogsdata'}); });
routes.get('/about-us', function(req, res){ res.send('<h1>Lucius Websystems</h1>Amsterdam, The Netherlands'); });
routes.get('/about/:name?', function(req, res){ var name = req.params.name; res.send('<h1>' +name +'</h1>About text'); });
/* GET Blog detail page. */
routes.get('/blog/:blogid', function(req, res, next) {
// Place json data in a var.
var blogsdata = req.app.locals.blogsdata;
// Create array.
var blogItem = [];
// Check and build current URL
var currentURL = '/blog/' + req.params.blogid;
// Lop through json data and pick correct blog-item based on current URL.
blogsdata.forEach(function (item) {
if (item.title == currentURL) {
blogItem = item;
}
});
if (blogItem.length == 0) {
// Render the 404 page.
res.render('404', {
title: '404',
body: '404'
});
} else {
// Render the blog page.
res.render('blog-detail', {
blog: blogItem
});
}
});
module.exports = routes;
From the CLI error, it appears no blog data is even returned to be read into the array.
I have carefully gone through the tutorial several times and I think there are steps that may be implied that I am missing.
Can someone please help me understand how to get the blog data so that it can be read into the array and output to my template?
Also open to troubleshooting suggestions in comments.
Thanks for reading!
The error is raising in this line:
blogsdata_all.blogs.forEach(function(item){
As the error says, blogs is undefined.
If there is an error in the request or status code isn't 200, the body is not assigned to the variable, but you are not finishing the execution, so the variable in that case would be undefined.
Other possible problem is the json received doesn't have blogs as key of the body.
Check this both things and let us know if you found the problem

Match a request parameter with a JSON Object with node.js and the express framework

The Code works fine with the uncomment lines.
But when i activate the else Statement i get every times the 'not found' even there is a match between req.params.code and data.airports[i].code.
var express = require('express');
var data = require('./data.json');
var app = express();
app.use(express.static('public'));
app.set('view engine', 'jade');
app.get('/', function (req, res) {
res.render('index', { title: 'Startseite', message: 'index.html'});
});
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code == data.airports[i].code) {
res.render('iata-code', data.airports[i]);
/* } else {
res.send('not found'); */
};
};
});
app.listen(80, function () {
console.log('Example app is running!');
});
Edit:
I change the code to:
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code === data.airports[i].code) {
res.status(200).render('iata-code', data.airports[i]);
} else {
res.status(404).send({ error: 'Something failed!' });
};
};
});
even i send the http status code 404 before the headers i get the error in my console: Error: Can't set headers after they are sent.
Edit2:
app.get('/de-de/code/:code', function (req, res) {
for (var i in data.airports) {
if (req.params.code === data.airports[i].code) {
res.writeHead(200, { "Content-Type": "text/html" });
res.render('iata-code', data.airports[i]);
} else {
res.writeHead(404, { "Content-Type": "text/html" });
res.write('Something failed!');
res.end();
};
};
});
Edit3: I set up an alternative way. But this is also not working. I am New to node.js but i still dind't find a solution.
var express = require('express');
var data = require('./data.json');
var airports = data.airports;
var app = express();
function filterData (reqCode) {
var result = {};
for (var i in airports) {
console.log('-----');
console.log(i + ': ' + reqCode + ' <--> ' + airports[i].code);
console.log('-----');
if (airports[i].code === reqCode) {
result = airports[i];
} else {
result = {};
};
};
return result;
console.log(result);
};
app.get('/de-de/:code', function (req, res, next) {
var reqCode = req.params.code;
if (filterData(reqCode) === {}) next('route');
else next();
}, function (req, res, next) {
res.write('200');
res.end();
});
app.get('/de-de/:code', function (req, res, next) {
res.write('404');
res.end();
});
app.listen(80, function () {
console.log('Example app is running! Cancel Server with CTRL + C');
});
Your else is inside the for loop, so whenever req.params.code == data.airports[0].code doesn't return true (first pass), it will return not found, instead of going through the next candidate.
You are sending response more than one that's why you are getting this issue.
Instead of res.send() you should use res.write() to send multiple responses.
res.send() sends entire HTTP response to the client includes headers and content even it ends the response.
And after that, you can't send anything.
Note:
After completing loop you can finally call the res.send() if it requires for you.

How to have express handle and capture my errors

var database = require('database');
var express = require('express');
var app = express();
var cors = require('cors');
app.use(cors());
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({
extended: false
});
app.post('/dosomething', urlencodedParser, function(req, res) {
if (!req.body.a) {
res.status(500).send(JSON.stringify({
error: 'a not defined'
}));
return;
}
firstAsyncFunction(req.body.a, function(err, result) {
if (err) {
res.status(500).send('firstAsyncFunction was NOT a success!');
} else {
if (result.b) {
secondAsyncFunction(result.b, function(err, data) {
if (err) {
res.status(500).send('secondAsyncFunction was NOT a success!');
return;
}
res.send('EVERYTHING WAS A SUCCESS! ' + data);
});
}
else {
res.status(500).send('result.b is not defined');
}
}
});
});
function firstAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
function secondAsyncFunction(param, callback) {
//Some network call:
// Return either return (callback(null,'success')); or return (callback('error'));
var query = database.createQuery(someOptionsHere);
database.runDatabaseQuery(query, function(err, entities, info) {
if (err) {
return (callback('error'));
}
return (callback(null, 'success'));
});
};
var server = app.listen(process.env.PORT || 3000, function() {
var host = server.address().address;
var port = server.address().port;
console.log('App listening at http://%s:%s', host, port);
});
module.exports = app;
I have here a basic express http server. This server has one route, dosomething, which makes two network calls and tells the user if they were a success or not.
This is my entire webserver (this is a bare bones server of my actual server for example purposes). I am now concerned with this server crashing. Reading the docs for express I see there is a default error handler which will catch errors and prevent the server from crashing (http://expressjs.com/en/guide/error-handling.html). I have added the code:
function defaultErrorHandler(err, req, res, next) {
if (res.headersSent) {
return next(err);
}
res.status(500);
res.render('error', { error: err });
}
app.use(defaultErrorHandler);
This still crashes my server though. For example. I had a problem with my database returning an improper JSON response and inside of my firstAsyncFunction (not shown in the code) I tried to parse the JSON and it caused an error telling me it was improper JSON and the server crashed and was unable to take requests anymore until I restarted it. I would like to avoid this and have the default error handler send out a generic response back to the user when this occurs. I thought if I specified the defaultErrorHandler and put it inside of app.use that it would capture and handle all errors, but this does not seem to be the case? Inside of my async function for example you can see I am looking if an error was returned and if it was I send an error back to the user, but what if some other error occurs, how can I get express to capture and handle this error for me?
The defaultErrorHandler cannot handle exceptions that are thrown inside asynchronous tasks, such as callbacks.
If you define a route like:
app.get('/a', function(req, res) {
throw new Error('Test');
});
An error will be thrown, and in this case defaultErrorHandler will successfully catch it.
If the same exception occurs in an async manner, like so:
app.get('/a', function(req, res) {
setTimeout(function () {
throw new Error('Test');
}, 1000);
});
The server will crush, because the callback is actually in another context, and exceptions thrown by it will now be caught by the original catcher. This is a very difficult issue to deal with when it comes to callback.
There is more than one solution though. A possible solution will be to wrap every function that is prone to throw error with a try catch statement. This is a bit excessive though.
For example:
app.get('/a', function(req, res) {
setTimeout(function () {
try {
var x = JSON.parse('{');
}
catch (err) {
res.send(err.message);
}
}, 1000);
});
A nicer solution:
A nicer solution, would be to use promises instead, if it's possible, then for example you can declare a single errorHandler function like so:
function errorHandler(error, res) {
res.send(error.message);
}
Then, let's say you have to following function with fetches stuff from the database (I used setTimeout to simulate async behavior):
function getStuffFromDb() {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("{");
}, 100);
});
}
Notice that this function returns an invalid JSON string. Your route will look something like:
app.get('/a', function(req, res) {
getStuffFromDb()
.then(handleStuffFromDb)
.catch(function (error) { errorHandler(error, res) });
});
function handleStuffFromDb(str) {
return JSON.parse(str);
}
This is a very simplified example, but you can add a lot more functionality to it, and (at least theoretically) have a single catch statement which will prevent your server from crushing.

express unit testing, calling close on server results in `call of undefined`

I am attempting to test drive an node.js application based on express. I want to return a simple 404.html, which I can successfully do, but afterward, calling close on the node http server gets this error:
Fatal error: Cannot call method 'call' of undefined
I am having a hard time tracking down what is undefined because the same method works beautifully when called elsewhere.
Here is my express code:
function Server() {
this.port = 9000;
this.staticDir = '/public';
}
function handleHomeRequest(req, res) {
var body = '<html><body>Home Page.</body></html>';
res.send(body);
}
Server.prototype.start = function () {
expServer = express();
expServer.get('/', function (req, res) { handleHomeRequest(req, res); });
expServer.use(function (req, res) {
res.status(404).sendfile('./src/public/404.html');
});
runningServer = expServer.listen(this.port);
};
Server.prototype.stop = function (cb) {
runningServer.close(cb);
};
Here is my nodeunit test code:
var ROOT_URL = 'http://localhost',
PORT = 9000,
URL = ROOT_URL + ':' + PORT + '/',
http = require('http'),
Server = require('./server.js'),
server;
exports.setUp = function(done) {
server = new Server();
done();
};
exports.tearDown = function (done) {
server = null;
done();
};
exports['Requesting a page that does not exist results in a 404.'] = function (test) {
server.start();
httpGet(URL + 'guaranteedNotToExistPage', function(res, data) {
test.equal(404, res.statusCode, 'Requesting a page that dne did not return with a status code of 404.');
test.ok(data.indexOf('404 Page Not Found') > -1, 'The 404 page was not returned.');
//test.done();
server.stop(test.done);
});
};
function httpGet(url, callback) {
var request = http.get(url),
receivedData = '';
request.on('response', function (response) {
response.setEncoding('utf8');
response.on('data', function (chunk) {
receivedData += chunk;
});
response.on('end', function () {
callback(response, receivedData);
});
});
}
The result of the http get request come back, the failure only occurs when I call server.stop(test.done); however, stopping the server is required to ensure my unit tests can be run in any order and independent.
First, where runningServer is defined? I can't see a
var runningServer;
anywhere in the first peace of code.
So, if you write a value in prototype.start I doubt you can access it on prototype.stop that is a different scope.
Second, {expressListener}.close() in node 0.6 was just synchronous, they added the callback on the 0.8. So, check the node.js version to be sure that the {cb} is correctly handled.

Categories

Resources