I am new to nodejs but I did get something to work last night with mongodb on a IIS server with iisnode. :)
But I am wondering over one thing which seems to be a refresh bug or something.
When I go to "http://localhost/mongo.js" in my browser the results will just be "[]" the first time. If I hit refresh the results will be what I expected (an json array with persons). Dosen't this seems wrong?
Let's say now I do it with a query, "http://localhost/mongo.js?name=Daniel", and get all Persons with the name Daniel. The response the first time will be "all the persons" because that's what we asked for above, and when I hit refresh the results will be all the Persons named Daniel. Why is this happening?
It seems that the server cached the query's i've made, and I don't want to hit refresh everytime to get the correct results.
This is my code I am using: (also available here http://pastebin.com/PnVfrQmh)
/* GLOBALS
----------------------------------------------------------------------*/
var rdata = [];
/* SERVER SETTINGS
----------------------------------------------------------------------*/
//load http module to ceate an http server.
var http = require('http');
var url = require('url');
//configure to respond http server with message
http.createServer(function (request, response) {
//request name parameter
var url_parts = url.parse(request.url, true);
var query = url_parts.query;
//do the mongo
var mongo = require('mongodb');
var db = new mongo.Db('nodedb', new mongo.Server('localhost', 27017, {}), {});
db.open(function() {
db.collection('Persons', function(err, collection) {
var cursor = collection.find(query);
cursor.each(function(err, doc) {
if(doc) {
rdata.push(doc);
}
});
});
});
//write what type of response
response.writeHead(200, {'Content-Type': 'application/json;charset=utf-8'});
//return data json array
response.end(JSON.stringify(rdata));
//clear rdata
rdata = [];
}).listen(process.env.PORT);
You have to remember that you are always in an async world with node.js. This caught me out as well coming from a more sync background.
What is happening here is your response is returning before the logic is run. This is because when you call db.open(function() { this goes on the event loop and returns. This is non-blocking so the next line of code that runs is response.writeHead(200, {'Content-Type': 'application/json;charset=utf-8'});. Then the callback for db.open is called, sometime in the future.
In order to correct this. return the response after the cursor.each(function(err, doc) { loop is finished.
Hope this helps.
Related
I am trying to get the API response time from a website with cheerio. I have to wait first though for the site to fetch the time, though I am not sure how exactly to do that. Here is what I have tried. At the moment it does not work because it doesnt wait for the website to fetch the time.
request.get("site", function (err, res, body) {
if (!err) {
var $ = cheerio.load(body);
$('.metrics-container').filter(function(){
var data = $(this);
var response_time_api = data.children().children().children()[1].children;
console.log(response_time_api)
});
}
});
here is the image from the source am fetching
I am trying to do a simple xhttp GET request to an express.js server. Unfortunately I get no response data with this code. The connection is fine as I have successfully used "res.send" to send a body back from the server.
I am not sure if my use of "findOne" on the server is incorrect or if my use of xhttp on the client is incorrect. I suspect it is the client.
I'd appreciate any advice.
* CLIENT CODE *
function getfood() {
var xhttp = new XMLHttpRequest();
xhttp.open("GET", "http://localhost:3000/clientfood", true);
xhttp.send();
}
* SERVER CODE - Express.js / Node *
app.get('/clientfood', cors(), (req, res) => {
//res.send('test'); //this works at least
db.collection('quotes').findOne({
"_id": ObjectId("12345")
},
{
name: 1,
quote: 1
})
})
xhttp GET request to an express.js server - nothing returned
Your server code does not return a response. You need to do something like res.send(...) or res.json(...) to return a response back to the caller and you need to do that in the callback that your database provides for communicating back the result of a query (in most DBs, you can either use a plain callback or a promise).
Your client code does not listen for a response. Example for how to do that shown here on MDN and would typically be:
function getfood() {
var xhttp = new XMLHttpRequest();
xhttp.addEventListener("load", function() {
if (xhttp.status === 200) {
// have data in xhttp.responseText, process it here
} else {
// got some other response here
}
});
xhttp.open("GET", "http://localhost:3000/clientfood", true);
xhttp.send();
}
Thanks so much - especially #jfriend00. I have a lot to learn about how these frameworks work. After taking your advice about SEND I had a little trouble seeing the result on my frontend. I got the message "promise pending". I fixed that with the code suggested in this post.
Express - Promise pending when loop queries
Also I modified my findOne function to grab the entire object for my id.
Final code:
app.get('/clientfood', cors(), (req, res) => {
mydata = db.collection('quotes').findOne(
{
"_id": ObjectId("12345")
})
// promise code
Promise.all([mydata]).then(listOfResults => {
res.send(JSON.stringify(listOfResults)) //for example
}, err => {
res.send(500, JSON.stringify(err)); // for example
});
})
I'm using node js, express and postgresql as backend.
This is the approach I used to make a rest API:
exports.schema = function (inputs, res) {
var query = knex('schema')
.orderBy('sch_title', 'asc')
.select();
query.exec(function (err, schemas) {
if(err){
var response = {
message: 'Something went wrong when trying to fetch schemas',
thrownErr: err
};
console.error(response);
res.send(500, response);
}
if(schemas.length === 0){
var message = 'No schemas was found';
console.error(message);
res.send(400, message);
return;
}
res.send(200, schemas);
});
};
It works but after a while postgres logs an error and it's no longer working:
sorry, too man clients already
Do I need a close each request somehow? Could not find any about this in the express docs. What can be wrong?
This error only occurs on production server. Not on developing machine.
Update
The app only brakes in one 'module'. The rest of the app works fine. So it's only some queries that gives the error.
Just keep one connection open for your whole app. The docs shows an example how to do this.
This code goes in your app.js...
var Knex = require('knex');
Knex.knex = Knex.initialize({
client: 'pg',
connection: {
// your connection config
}
});
And when you want to query in your controllers/middlewares...
var knex = require('knex').knex;
exports.schema = function (req, res) {
var query = knex('schema')
.orderBy('sch_title', 'asc')
.select();
// more code...
};
If you place Knex.initialize inside an app.use or app.VERB, it gets called repeatedly for each request thus you'll end up connecting to PG multiple times.
For most cases, you don't need to do an open+query+close for every HTTP request.
I am trying to setup a simple mongoose test server that reads users in the Users collections and prints the username. I can't seem to get the res.write for the query data to show up at the client side
var mongoose = require('mongoose');
var db = mongoose.createConnection('localhost', 'bugtraq');
var schema = mongoose.Schema({ username : 'string', email : 'string' });
var User = db.model('User', schema);
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
User.find().exec(function (err, users) {
if(err) { res.write(err.message); }
if(users) {
users.forEach(function(u){
console.log(u.username);
return '<b>'+u.username+'</b>';
});
}
});
res.write('</body></html>');
res.end();
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');
The server side output is
<html><head></head><body></body></html>
I do see the username in the console output
Any pointers welcome
You have two problems. First, the mongoose query is anynchronous, yet you're ending your response outside of it's callback, before the query actually happens (I had to reindent the code to make sure).
To make it work you'd need to end the response inside the callback function for User.find.
Secondly, you're not collecting output as you think. This line is wrong:
return '<b>'+u.username+'</b>';
You're returning the output of the find into thin air. You'll need to capture it if you want to return it in the response.
Putting it together, it might look something like this:
User.find().exec(function (err, users) {
if(err) { res.write(err.message); }
if(users) {
// here make a buffer to store the built output ...
var output = [];
users.forEach(function(u){
// (you saw this console output because this loop is happening, it's
// just happening after your response has been ended)
console.log(u.username);
// ... then in each iteration of the loop, push to the buffer
output.push('<b>'+u.username+'</b>');
});
}
// finally, finish the response in the `find` callback.
res.end(output.join() + '</body></html>');
});
Here is the thing :
I have a client which sends data to a server. This server has to contact an external A.P.I. and send back its response to the client. I just can't figure out how and where I can contact the external A.P.I once the server has got the client data.
I route client data like this :
app.post('/getAutoComplete', routes.read);
routes.read retrieves the data within req.body. With my nodejs version (without express framework), I then request the api this way :
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
The problem is that i'd like to use native expressJS method like app.post but I don't know how because :
Express (app) object is not available here (declared in app.js but not in the route file)
I don't know how to send POST data with app.post
Any suggestion ?
app.post('/getAutoComplete', routes.read);
// assuming routes.read lookes something like this
routes.read = function read(req, res) {
var http = require('http'), options = {
host : "192.168.1.38",
port : 8080,
path : "/myURL",
method : 'POST'
};
var webservice_data = "";
var webservice_request = http.request(options, function(webservice_response)
{
webservice_response.on('error', function(e){ console.log(e.message); });
webservice_response.on('data', function(chunk){ webservice_data += chunk;});
webservice_response.on('end', function(){res.send(webservice_data);});
});
webservice_request.write(req.body);
webservice_request.end();
};
Also check out https://github.com/mikeal/request It's the de-facto module for doing web requests in node.
routes.read is a function. You can call it with extra parameters, so for example
app.post('/getAutoComplete', function(req,res) {
var q = req.query.q; // or whatever data you need
routes.read(q, function(err, response) {
if (err) throw err;
return res.json(response);
});
});
Now make the routes.read function use the first parameter as the query and when it's gathered the response from the remote API, call the second parameter with any error as the first parameter and the response as the second one.
Update This answer has already been picked as an answer, but it'd be more helpful if I showed an example of routes.read, too:
routes.read = function(q, cb) {
// pretend we calculate the result
var result = q * 10;
if (result > 100) {
// call the callback with error set
return cb("q value too high");
}
// all is well, use setTimeout to demonstrate
// an asynchronous return
setTimeout(function() { cb(null, result) }, 2000);
};