I want to create a route which can change while the program is running.
Example : app.get('/',function(req,res){/*Something here*/}; This is a normal route.
I want to replace the '/' with a variable which can be replaced with a random number. After that I'll create a qrcode with a nodejs module and the user who scans this qrcode will confirm a kind of transaction.
If you understand my idea and you have a solution, I'll take it.
As #Louy said, use parameters:
var getQRCode = require('./yourQRCodeModule');
app.param('qrcode', function(req, res, next, qrcode) {
// qrcode will be "1234" if your request path was "/1234"
console.log('checking qrcode: %s', qrcode);
// get the qrcode from some asynchronous function
getQRCode(qrcode, function callback(err, qrcode) {
// if this number was not a valid dynamic path, return an error from your module
console.log('qrcode was %s', (!err && qrcode) ? 'valid' : 'invalid');
if (err) {
next(err);
} else if (qrcode) {
req.qrcode = qrcode; // object from your module
next();
} else {
next(new Error('failed to load QR code'));
}
});
});
app.get('/:qrcode', function (req, res) {
// req.qrcode will be the object from your module
// if the number was invalid, this will never be called
});
What I'm trying to point out is that you're thinking of this scenario differently than how express approaches the problem. You want a one-time route with a specific qrcode, but these kind of routes don't exist in express. So here's what I understand your ideal solution to look like:
server creates "azjzso1291084JKioaio1" for a qrcode
you register something like app.getOnce("azjzso1291084JKioaio1", function(req, res){...})
first time the request gets called, it's removed from your express router
Here's what I'm suggesting:
server creates "azjzso1291084JKioaio1" for a qrcode
your module stores this qrcode either in a database or in memory, within your module, e.g. var qrcodes = {}; qrcodes["azjzso1291084JKioaio1"] = {some: 'object'};
your app.param asynchronous function based on the example given in step 2 could look like this:
// yourQRCodeModule.js
var qrcodes = {};
qrcodes["azjzso1291084JKioaio1"] = {some: 'object'};
module.exports = function getQRCode(qrcode, callback) {
if (qrcodes[qrcode]) {
var obj = qrcodes[qrcode]; // copy object
delete qrcodes[qrcode]; // remove from memory here
callback(null, obj);
} else {
// invalid path
callback(new Error('invalid QR code'), null);
}
};
Now notice if you request /azjzso1291084JKioaio1 twice, the second time fails. This is how you intend it to work, if I am not mistaken.
Related
I am working with node.js in visual studio code. Still new to both.
I am trying to call a nested variable with child properties from one js file to use in another file. How can this be done?
I have already referenced the source file in my target file and I am able to call to the file and method that contains the variable which return object.object in console.log. Any calls to the variable itself or to the object assigned to its value come back undefined. I have tried using exports.var but visual studio code does not recognize the command. The object assigned to its value does have an initial global declaration in the source file.
job and its children is the value I want to transfer over. Console.log command in source file does display the expected values.
Source File: dataHandler.js
let jobArray = null;
export function getJobDetails() {
if(_jobDetails == null) {
let job, jobIndex, regIndex;
regIndex = _productTypes.indexOf("reg");
jobIndex = (regIndex > -1) ? regIndex : 0;
job = _jobsData[jobIndex].details;
jobArray = job;
}
console.log(jobArray.orderId); //returns expected value
return _jobDetails;
}
Target File: geo.js
import * as DataHandler from './dataHandler.js';
export function createGeo() {
var site = DataHandler.jobArray.orderId;
//var site = DataHandler.getJobDetails().jobArray;
//var site = DataHandler.getJobDetails(jobArray.orderId);
Do something like following.
const DataHandler = require('./dataHandler');
var test = DataHandler.getJobDetail();
console.log(test.orderId);
& DataHandler should do something like following. Here important point is I'm returning jobarray from getJobDetails.
var jobArray = null;
var getJobDetail = () => {
jobArray = {
orderId: 1
};
return jobArray;
};
module.exports = {
getJobDetail
};
Express's app and Socket.io have nothing to do with one another.
So fundamentally, you can't use socket inside app.post.
You need to identify the client. You can use Passport which has a Socket.io plugin that essentially bridges the app.post/get's req.user to socket.request.user.
Note: It doesn't have to be an authenticated client with user that's fetched from database, just a client with a temporary user stored in memory would do. Something like this:
app.use(function(req, res, next) {
if (!req.user) { // if a user doesn't exist, create one
var id = crypto.randomBytes(10).toString('hex');
var user = { id: id };
req.logIn(user);
res.redirect(req.lastpage || '/');
return;
}
next();
});
var Users = {};
passport.serialize(function(user) {
Users[user.id] = user;
done(null, user);
});
passport.deserialize(function(id) {
var user = Users[id];
done(null, user);
});
Then you can attach the client's socket ID to its user session.
io.on('connection', function (socket) {
socket.request.user.socketid = socket.id
});
And then instead of socket.emit use io.emit in app.post using the socketid
app.post('/', function (req, res) {
io.to(req.user.socketid).emit('whatever');
});
Note: io.to() is used to emit to a room, but every socket is by default joined to the same room named as its socket.id, so it'll work.
thanks : https://stackoverflow.com/questions/28310418/nodejs-accessing-nested-variable-in-global-scope
You are not returning "jobArray", Use Promise to return the variable to your child file.
I am fairly new to NodeJS and asynchronous programming. I've never been seriously into JavaScript until I started working on a project that required me to set up a REST API using node server and I started working on it for the past day or two. I'm trying to set up a modular application and have been successful in setting up a route, model and controller using Express JS.
I use express to read the request bodies to get data posted to the server in JSON. But my current situation came up when I tried to pass certain data from my routes module (or file) to my controller in a function call.
When I couldn't read the data I tried to log it and to my surprise the JSON Object that I passed as an argument is now logged as a [Function].
Here is how I pass the data:
routes.js
var express = require('express');
var UserCtrl = require('./controller');
var user = express.Router();
// Define routes
// Request to list all users.
user.get('/', function (req, res){
UserCtrl.getAll(function (result){
res.json(result);
});
});
user.post('/create', function (req, res){
var postData = {
'firstName': req.body.firstName
};
UserCtrl.create(function (postData, result){
res.json(result);
});
});
module.exports = user;
controller.js
var Users = require('./model');
// list all users
module.exports.getAll = function (callback) {
Users.findAll(callback);
}
// create user
module.exports.create = function (postData, callback) {
console.log(postData);
// create user by passing the user to a model
Users.create (newUser, callback);
}
May be I've got the basics wrong or may be this is completely a mistake of my code. Should I make the controller also an express middleware?
This code calls create. The first value sent to it is a function. This function that you send to create takes in a postData and a result value.
UserCtrl.create(function (postData, result){
res.json(result);
});
This code is what is getting called. The first thing that gets sent in is postData. When you called it just above you sent in a function to that first thing. So console.log will output function.
module.exports.create = function (postData, callback) {
console.log(postData);
// create user by passing the user to a model
Users.create (newUser, callback);
}
Perhaps you meant to send in that postData object first?
user.post('/create', function (req, res){
var postData = {
'firstName': req.body.firstName
};
// This is the changed line
UserCtrl.create(postData, function (postData, result){
res.json(result);
});
});
I need to set a ReST API with my NodeJS Express 4 Application.
Currently, this is my API.
I have a families resource which exposes several HTTP verb.
GET to perform a read in my MongoDB database.
GET with familyID to get the family with the id familyID
POST to create a new family in the database.
PUT to update a family.
I want to follow the ReSTful theory so I'd like to control when a PUT is done that all the resource is modified and not a part of it (which is a PATCH verb).
This my nodejs route controller code :
// Main Function
router.param('famillyId', function(req, res, next, famillyId) {
// typically we might sanity check that famillyId is of the right format
Familly.findById(famillyId, function(err, familly) {
if (err) return next(err);
if (!familly) {
errMessage = 'familly with id ' + famillyId + ' is not found.';
console.log(errMessage);
return next(res.status(404).json({
message: errMessage
}));
}
req.familly = familly;
next();
});
});
/PUT
router.put('/:famillyId', function(req, res, next) {
console.log('Update a familly %s (PUT with /:famillyId).', req.params.famillyId);
req.familly.surname = req.body.surname;
req.familly.firstname = req.body.firstname;
req.familly.email = req.body.email;
req.familly.children = req.body.children;
req.familly.save(function(err, familly) {
if (err) {
return next(err);
}
res.status(200).json(familly);
});
});
I'd like to know what is the best way to do this control. I don't want to use a series of 'if' for each record of my JSON object. Is there an automatic way of doing it ?
Just to avoid this kind of code :
if (req.familly.surname)
if (! req.body.surname)
return next(res.status(200).json('{"message":"surname is mandatory"}‘)));
Doing this kind of things for each property in my JSON Object is very boring, lots of code to type for nothing.
I looking forward a clean code to do it.
Thanks.
Hervé
var control = ['surname', 'firstname', 'email', 'children'];
control.forEach(function(arg){
if(!req.body[arg]){
return next(res.status(200).json({"message": arg + " is mandatory"}));
}
});
I am trying to developpe an API with NodeJs which accepts an object containing multiple queries to mongdb and answers an object with the different results (in fact Json).
I use express and my code is :
var nb_query=0;
var results;
//api
app.get("/api/:p",api);
function api(req, res) {
var jsonq=decodeURIComponent(req.params.p);
//console.log(jsonq);
var queries=JSON.parse(jsonq);
nb_query=Object.keys(queries).length;
results={};
for(var nq in queries) { // for each query
do_find_query(nq,queries[nq], function() {
//todo : managing head
res.end(JSON.stringify(results));
}
);
}
} // end of api function
function do_find_query (name_query,query,callback) {
var collection=fdb.collection(query.collection);
collection.find(query.find,query.fields,query.options).toArray(function(err,docs) {
if(err) throw err;
results[name_query]=docs;
nb_query--;
if(nb_query==0)
callback();
}
);
}
As you see, I use global vars to store the results and the counter nb_query. And I ask myself if it is a problem or not (now no because I am alone on the server, but when we will be thousands of billions? :-) ).
As I understand Node, there is only one thread and I think Node will finalize a started job unless he encoutered an io access. In this case, he stacks the io with the callback, and begins to answer to a new request.
If this is correct, I think that Node could answer to 2 or more different calls to my api (which need mongo calls) and so store different values in global vars which is shared (there's only one thread).
If this is right, I would also know what is the best way to change it.
I have the idea of declaring results and nb_query in api function and pass it to do_find_query, but nb_query isn't an object and is so not changed correctly.
I know I can put nb_query in an object to pass it 'by reference', but I want to know first if it is necessary and if it is a good way or if there is a better one.
Thanks for your help !
Doom.
------------------------------------------------------------------------------
EDIT :
I have change my code and it seems to work without global vars and without async library (which is for me using a hammer to swat a fly)
//api
app.get("/api/:p",api);
function api(req, res) {
var jsonq=decodeURIComponent(req.params.p);
//console.log(jsonq);
var queries=JSON.parse(jsonq);
var query_names=Object.keys(queries);
var results={};
var query_left=query_names.length;
query_names.map( function(query_name) {
var query=queries[query_name];
var collection=fdb.collection(query.collection);
collection.find(query.find,query.fields,query.options).toArray(function(err,docs) {
if(err) throw err; //todo : handle errors in a better way
results[query_name]=docs;
if(--query_left==0)
res.json(results);
}
);
}
);
}
But I still do not know if this is necessary to do or not. (I think so but I am new in Node so ...)
Thanks to mscdex as his answer make me known res.json() and help me understand scope of variable.
Instead of using globals, try this (uses the async module):
var async = require('async');
// ...
app.get('/api/:p', api);
function api(req, res) {
var jsonq = decodeURIComponent(req.params.p),
queries = JSON.parse(jsonq),
keys = Object.keys(queries),
queriesLeft = keys.length,
results = {};
async.each(keys, function(name, cb) {
var query = queries[name],
collection = fdb.collection(query.collection);
collection.find(query.find, query.fields, query.options)
.toArray(function(err, docs) {
if (err) return cb(err);
results[name] = docs;
cb();
}
);
}, function(err) {
if (err) throw err; // TODO: handle better
res.json(results);
});
} // end of api function
Is it possible to reuse / call the blueprint function (find/create/update/destory) and just add some items needed for the controllers. I'm sorry if I'm having hard time expressing my question but hopefully my example will help.
Example:
modue.exports = function(){
index: ....,
create: function(req, res){
try{
// i want to call the blueprint here to save some things
create(req, res);
// then do more after creating the record
....
}catch(err){
// want to catch some error here like validation err
// instead of sending it to res.serverErr();
}
}
....
}
//File api/controller/UserController.js
// suppose the model is User under api/models
modue.exports = {
create: function(req,res){
// pass req.query to User Model's Create function, so you dont need to rewrite all
//optional paramters for this overwrite version
User.create(req.query).exec(function(e, r){
if(e){
// !!!try to create in a different way!
}
})
}
}
You need to first copy blueprint folder from sails which is present in node_modules folder
Paste the blueprint folder in you api folder
Then in your controller for e.g UserController include actionUtil for e.g
var actionUtil = require('sails/lib/hooks/blueprints/actionUtil');
module.exports = {
create: function (req, res) {
// paste code from blueprint create.js file
var Model = actionUtil.parseModel(req);
// Create data object (monolithic combination of all parameters)
// Omit the blacklisted params (like JSONP callback param, etc.)
var data = actionUtil.parseValues(req);
// Create new instance of model using data from params
Model.create(data).exec(function created(err, newInstance) {
// Differentiate between waterline-originated validation errors
// and serious underlying issues. Respond with badRequest if a
// validation error is encountered, w/ validation info.
if (err)
return res.serverError({status:500, message:'error', err: err});
// If we have the pubsub hook, use the model class's publish method
// to notify all subscribers about the created item
if (req._sails.hooks.pubsub) {
if (req.isSocket) {
Model.subscribe(req, newInstance);
Model.introduce(newInstance);
}
// Make sure data is JSON-serializable before publishing
var publishData = _.isArray(newInstance) ?
_.map(newInstance, function (instance) {
return instance.toJSON();
}) :
newInstance.toJSON();
Model.publishCreate(publishData, !req.options.mirror && req);
}
// do your after create stuff here
// Send JSONP-friendly response if it's supported
res.ok({status: 200, message: 'ok', results: newInstance});
});
}
}