I'm trying to make a method in Meteor which reads a file and outputs the result. Below is my code.
Server:
Meteor.methods({
retTemplate: function(templateName){
var fs = Npm.require('fs');
var ret;
fs.readFile("./../../../../../client/" + templateName + ".html",{encoding: 'utf8'}, function(err, data) {
if(err)
return "ERROR";
console.log(data);
return data;
});
}
});
Client:
Meteor.call('retTemplate', submitName, Meteor.user(), function(e, r){
console.log(r);
$('#editTempData').val(r);
});
The code on the server side works (the server-side console is updated with the content of the html file), but the method is returning undefined to the client. I believe this is due to Meteor's asynchronous functions. Is there a way around this? I've been fiddling around for a bit to no avail.
Thanks.
EDIT: I think it would work if there weren't a readFile method called, because that sets up a bit of a double-asynchronous call, which might be the problem, but I don't know how to fix it.
You can't return a value from an asynchronous method and then return it to the client like that. Here is an alternative (but not ideal) solution.
Create a new Meteor.Collection on the client/server and simply subscribe subscribe/publish this collection. Save the data returned from fs.readFile() into your collection, and your client will be automagically notified when this occurs.
I found the answer. I needed to use Futures.
Working server:
Meteor.methods({
retTemplate: function(templateName){
var Future = Npm.require('fibers/future');
var fut = new Future();
var fs = Npm.require('fs');
var ret;
fs.readFile("./../../../../../client/" + templateName + ".html",{encoding: 'utf8'}, function(err, data) {
if(err)
return "ERROR";
console.log(data);
fut['return'](data);
});
return fut.wait();
}
});
Related
I need to insert a string defined in Javascript into an MSSQL table.
This is what I have so far:
Javascript:
var message = "It's a great day today!";
$.post('www.server.com/message='+message, function(response){
console.log(response);
});
Node.js Server:
//..... a bunch of code has been used to accept the HTTP request and get the message...
// for the purpose of this example, the message is asigned to 'NodeMsg'
var mssqldb = require("../core/mssql");
var NodeMsg = theMessageReceivedFromHTTPRequest;
function saveMessage(message) {
mssqldb.executeMssql("insert into messages (message, status) VALUES('"+message+"', 'new')", function (err) {
if (err) {
httpMsgs.show500(req, resp, err);
}//end if
else {
httpMsgs.sendJson(req, resp, 'success');
}//end else
});
};
mssql.js (node.js file):
var mssqldb = require("mssql");
var settings = require("../settings");
exports.executeMssql = function(sql, callback) {
var conn = new mssqldb.Connection(settings.mssqlConfig);
conn.connect()
.then(function(){
var req = new mssqldb.Request(conn);
req.query(sql)
.then(function (recordset) {
callback(recordset);
})
.catch(function(err){
console.log(err);
callback(null, err);
});
})
.catch(function(err){
console.log(err);
callback(null, err);
});
};//end executeMssql
Summary of what is going on:
I am defining a message as string. (note that it contains an single quote)
I am sending that string to the Node.js server
I am using Node.js to send the string to mssql
The Problem:
After learning more about Object Oriented Program, I have come to the realisation that the way I am performing the insert is highly frowned upon because It is open to SQL injection. Also, the code will break during the execution of the SQL query because of the single quote in the string.
The solution:
According most resources I have found, the solution is to use "Prepared Statements".
My Issue:
How on earth do I convert what I have already done, to utilise prepared statements? I have searched the web for HOURS and I cannot find one good example of how to do a prepared statement with Node.JS for MSSQL (not MySQL) which is comprehensible for a beginner to Node.Js
If you are using the Tedious cross-platform MSSQL driver implementation, the documentation is here: http://tediousjs.github.io/tedious/parameters.html
Basically you prepare a SQL statement with '#xxx' placeholders for values you need to inject, the you bind the actual values of those parameters to your request, then execute your request.
So i've been doing some reading and I think I have a general grasp on this subject but could use some insight from someone more experienced. I've been trying to write a simple RSS reader in Meteor and have been facing some issues with calling the Meteor method asynchronously. I currently define the method on the server(synchronously) and call it on the client(asynchronously). What I don't understand is that when I try to make the HTTP.call on the server, I return an undefined value passed to my client if I pass a callback into the request. But when I make the API request synchronously everything seems to work fine. Is this the normal behavior I should expect/the way I should be making the API call?
Meteor.methods({
getSubReddit(subreddit) {
this.unblock();
const url = 'http://www.reddit.com/r/' + subreddit + '/.rss';
const response = HTTP.get(url, {}, (err, res) => {
if(!err) {
//console.log(res.content);
return res;
} else {
return err;
}
});
}
});
Here's the method defined on the server side. Note that logging res.content shows that I'm actually getting the right content back from the call. I've tried reading some other answers on the topic and seen some things about using Future/wrapAsync, but I'm not sure I get it. Any help would be greatly appreciated!
The HTTP.get is doing async work, so callback passed to it will be called out of this meteor method call context.
To get desired result you should do it like this:
Meteor.methods({
getSubReddit(subreddit) {
// IMPORTANT: unblock methods call queue
this.unblock();
const url = 'http://www.reddit.com/r/' + subreddit + '/.rss';
const httpGetSync = Meteor.wrapAsync(HTTP.get);
try {
const response = httpGetSync(url, {});
//console.log(response.content);
return response.content;
} catch (err) {
// pass error to client
throw new Meteor.Error(...);
}
}
});
I have read all the questions on SO that I could find. They all use Express, Mongoose or they leave something out. I understand that Node.js is the server. I understand the MongoDB require is the driver the Node.js server uses to open a connection to the MongoDB. Then, on the server, I can do (from the documentation):
var MongoClient = require('mongodb').MongoClient;
var assert = require('assert');
var ObjectId = require('mongodb').ObjectID;
var url = 'mongodb://localhost:27017/test';
var findRestaurants = function(db, callback) {
var cursor =db.collection('restaurants').find( );
cursor.each(function(err, doc) {
assert.equal(err, null);
if (doc != null) {
console.dir(doc);
} else {
callback();
}
});
};
// Connect to the db
MongoClient.connect(url, function(err, db) {
assert.equal(null, err);
findRestaurants(db, function() { //I don't want to do this as soon as the server starts
db.close();
});
});
//if I put findRestaurant here,
function findRestaurant(data){
}
How do I call it from the client?
I do not want to find data as soon as I start the server. I realize those are examples, but what I cannot find is a way where the client requests some data and where the Node.js server returns it.
I have seen close examples using jQuery, Angular on the client, and then Express, Mongoose, Meteor, , etc.
All I want to understand is how I make this request from the client's browser. I can do that with XMLhttpRequest(), so I can put that part together, I believe. But, any example is appreciated.
But what is waiting on the Node.js side of things (how do I set up my function to be called once the server is listening)?
How do I create a function on the server side, maybe "GetRestaurants" and have that return the data it gets using find()?
I cannot find this information, this simple, anywhere. Is it too complicated to do the example without a framework?
I do not wish to copy and paste from something using Express, etc. without understanding what's going on. Most explanations never say, this goes on the Node.js side. This is client. I know I am expected to do my own research, but I am not putting it together, too used to RDBMSes, IIS, Apache, PHP, and so on.
I believe I have a fundamental misunderstanding of what's going on in the paradigm.
Please. No REST API creation, no frameworks of any kind on Node.js other than using the MongoDB library (unless there is an absolute requirement), not even jQuery, Angular, Jade, or anything else for the client side, straight up JavaScript on all sides.
I have seen questions like this,
How to display data from MongoDB to the frontend via Node.js without using a framework
But they do not show what I am asking. They do it all at once, as soon as the database connects. What if I want to do a delete or insert or find? There are many SO questions like this, but I have not hit the one that shows what I am looking for.
This should give the guidance. Once you go to a browser and type http://localhost:5155 the callback function (request, response) { will be called and the request to db will be made. Make sure you get response and then start working on the client side code:
const http = require('http');
const MongoClient = require('mongodb').MongoClient;
const assert = require('assert');
const url = 'mongodb://localhost:27017/test';
const server = http.createServer(function (request, response) {
getData(function (data) {
response.end(data);
});
});
function getData(callback) {
// Connect to the db
MongoClient.connect(url, function (err, db) {
assert.equal(null, err);
findRestaurants(db, function (data) {
db.close();
callback(data);
});
});
const findRestaurants = function (db, callback) {
const cursor = db.collection('restaurants').find();
const data = [];
cursor.each(function (err, doc) {
assert.equal(err, null);
data.push(doc);
if (doc === null) {
callback(data);
}
});
};
}
server.listen(5155);
I am having a tough time finding a solution to my problem online and was hoping someone on here might be able to help me. I have an express route that does a few API requests for different JSON objects. I would like to build a JSON response for my client side view but all of my attempts so far either yield previous request data or no data at all.
So my question to you JavaScript pros using node/express js. How do you sync up multiple sources of JSON objects into one single object to be returned to the client side in one response? Is there a library or some callback magic that you use?
Thanks in advance for any and all help!
Async is one of the more popular libraries for this purpose. There are many other async and promise libraries that can help with this. There are different methods that have different behaviors depending on what you need. I think series method is what you need, but check the documentation carefully.
var async = require('async');
var request = require('request');
app.get('endpoint',function(req, res){
async.series([
function(callback){request.get('url',callback)},
function(callback){request.get('url2',callback)},
function(callback){request.get('url'3,callback)},
],
function(err,results){
//handle error
//results is an array of values returned from each one
var processedData = {
a: results[0],
b: results[1],
c: results[2]
};
res.send(processedDAta)
})
})
You could also do this yourself (and is good practice for learning how to organize your node.js code).. callbackhell is a good write up of using named functions and modules to organize callbacks.
Here is a one possible way to do it. (Not tested)
app.get('/endpoint',function(req, res){
var dataSources = ['url1', 'url2',url3];
var requestData = [];
processRequestData = function(){
//do you stuff here
res.send(processedData);
};
dataSources.forEach(function(dataSource){
request.get(dataSource,function(err,result){
//handle error
requestData.push(result);
if(requestData.length == dataSources.length){
processRequestData();
}
})
})
});
Async.js(https://github.com/caolan/async) can help with tasks like this. A quick example:
app.get('/resource', function(req, res){
// object to send back in the response
var results = {};
// helper function to make requests and handle the data to results object
var getData = function(url, propertyName, next){
http.get(url, function(err, data){
// let async.js know if there is an error
if(err) return next(err);
// save data to results object
results[propertyName] = data;
// async.js needs us to notify it when each operation is complete - so we call the callback without passing any data back to
next();
});
};
// array of operations to execute in series or parallel
var operations = [];
operations.push(function(next){
getData('http://url-one', 'users', next);
});
operations.push(function(next){
getData('http://url-two', 'posts', next);
});
// async.js has a few options on how to execute your operations - here we use series
async.series(operations, function(err){
if(err){
throw err;
}
// if we get to this point, all of the operations have exectued and called
// next() without any errors - send the response with a populated results object.
res.send(results);
});
});
I haven't actually tried this code yet but it should give you a good idea on how to do it.
I'm using urllib to make a request to a webpage and I'm trying to return it's headers like so:
var getHeaders = function(webpage){
var info = urllib.request(webpage, {}, function(err, data, res){
// console.log(res.headers); works fine and shows them
return res.headers; // I thought it should make the info variable have the headers information
});
return info;
}
Now when I try to get the headers like maybe set-cookie of a webpage I intended it to return the that from the website but it doesn't, so is there a way to return the headers or is it just not possible to do that?
In Node pretty much everything is done asynchronously, so you'll just need your function to be asynchronous.
var getHeaders = function (webpage, done) {
urllib.request(webpage, {}, function(err, data, res){
done(err, res.headers);
});
}
The traditional pattern is to use callbacks that return an error as the first argument (or a falsy value in case everything went well), and whatever you need to return afterwards.
Consuming the method is then very similar to what you had to do with the urllib thing.
getHeaders(webpage, function (err, headers) {
if (err) {
throw err; // or, you know, deal with it.
}
console.log(headers);
});