Node.js request in function - node.js

I'm new to Node, and Javascript in general. I'm working with the request module to get a JSON response from a web service. I'm not sure if it'd be best to turn my request into a function, or embed the request inside of another function. I haven't had any luck either way.
// Module imports
var express = require('express');
var router = express.Router();
var request = require('request');
var options = {
url: 'https:www.example.com/wow.json',
auth: {
user: 'user',
password: 'pass',
json: true
}
}
request(options, function (err, res, body) {
if (err) {
console.log(err);
return;
}
requestResult = JSON.parse(body); // All data
wowUsage = requestResult.publishers[0].used;
});
// Sending data to the template view
router.get('/', function(req, res, next) {
res.render('template', {tempVar: wowUsage});
});
module.exports = router;
Whenever I start up my web server, this code executes once, and then it's done. Refreshing the page won't load any new information. Should I embed the request in a function, and then call that function in my router.get statement? I tried to nest the request in a function, but I couldn't make that work at all.

If you put the request in a separate function, make sure to add a callback parameter to the new function that gets called with the appropriate data. For example:
function getJSON(callback) {
request(options, function(err, res, body) {
if (err)
return callback(err);
try {
callback(null, JSON.parse(body).publishers[0].used);
} catch (ex) {
callback(ex);
}
});
}
router.get('/', function(req, res, next) {
getJSON(function(err, wowUsage) {
if (err) {
console.log(err.stack);
return res.status(500);
}
res.render('template', {tempVar: wowUsage});
});
});

Related

Call multiple modules in route Express, Nodejs

This is the first time I create an API. I've tried to delete the user items once, the user is removed. I was able to delete the user but i didn't succeed to delete the items.
User.js
express = require('express');
User = require('./user');
Item = require('../item');
router = express.Router();
User.findByIdAndRemove(req.params.id, function(err, user) {
if (err) {
return res.status(500).send('User not found by id.');
}
Item.deleteMany(user._id, function(err, item) {
if (err) {
return res.status(500).send('Item is not found');
}
return res.status(200).send(user, item);
});
});
Is there a way to achieve this? because I have a feeling that I'm doing it the wrong way.
Thanks!
It looks like you are not defining the actual routes -- you need
router.route('/').post(function(req, res){ ... });
You should also include the body parser to get the parameters out of the request
var bodyParser = require('body-parser');
app.use(bodyParser.json());
var parseUrlencoded = bodyParser.urlencoded({extended: false});
The code you have for User methods will look more like the below block. You can change '/' to the URL path you would rather have the api respond to and can change the code from being in .post to .delete depending on what method you want to respond to
route.route('/')
.post(parseUrlencoded, function(req, res) {
// code to respond to 'post' methods
if (!req.params.id) {
return res.send('id not sent')
}
User.findByIdAndRemove(req.params.id, function(err, user) {
if (err) {
return res.status(500).send('User not found by id.');
}
Item.deleteMany(user._id, function(err, item) {
if (err) {
return res.status(500).send('Item is not found');
}
return res.status(200).send(user, item);
});
});
})
.delete(parseUrlencoded, function(req, res) {
// code to respond to 'delete' method
})

NodeJs - calling one method from another in server controller

With the following controller, how can I call one method from another in the same controller?
Specifically, calling login() within a successful signup(), while retaining the same functionality for login() when it is used by a form?
The line this.login(newUser) does not work, nor does plain old login(newUser)
In both scenarios, I get the error:
TypeError: Cannot call method 'login' of undefined
var mongoskin = require('mongoskin');
module.exports = {
login: (function (req, res) {
req.db.collection('auth').findOne({_id: mongoskin.helper.toObjectID(req.body.id)},
function (err, results) {
// log person in and send results to client
}
)
}),
signup: (function (req, res) {
var user = req.body;
req.db.collection('auth').insert(user, function (err, newUser) {
// after adding user, automatically log them in
// does not work:
//login(newUser, function (err) {
// do something
//})
// does not work:
this.login(newUser, function (err) {
// do something
})
}
)
})
}
Controllers should be doing as little as possible, and should orchestrate the work required by executing functions stored elsewhere.
View this gist - click here
What I have done is created "services" that are not tied to the client request, therefore re-usable everywhere.
Hope this helps.
Thanks to Dave Newton
var mongoskin = require('mongoskin');
var myCollection = 'auth';
Solution
function localLogin(db, myCollection, user, res){
db.collection(myCollection).findOne({_id: mongoskin.helper.toObjectID(user._id)},
function(err, user){
res.send({ token: createToken(user) });
});
module.exports = {
login: (function (req, res) {
var user = req.body;
localLogin(req.db, myCollection, user, res)
},
signup: (function (req, res) {
var user = req.body;
req.db.collection(myCollection).insert(user, function (err, newUser) {
// after adding user, automatically log them in
localLogin(req.db, myCollection, newUser, res)
})
}
) }) }

PUT and DELETE always route to GET in Node + Express

I'm a beginner in Node/Express. I tried to make an CRUD application but stuck at update and delete. I think my router code is problematic but I don't know why. The following code is in my controller, everything works but PUT and DELETE. It always route to GET. I tried to use next(); but it returns this error: Can't set headers after they are sent..
I can make the delete works by using GET /:company_id/delete but it's not a good and standardized solution. How can I get update and delete process worked?
'use strict';
var Companies = require('../../models/companies');
module.exports = function (router) {
// INDEX
// accessed at GET http://localhost:8000/companies
router.get('/', function (req, res) {
Companies.find(function(err, model) {
if (err) {
res.send(err);
}
else {
res.format({
json: function () {
res.json(model);
},
html: function () {
res.render('companies/index', model);
}
});
}
});
});
// CREATE VIEW
// accessed at GET http://localhost:8000/companies/create
router.get('/create', function (req, res) {
res.render('companies/create');
});
// CREATE DATA
// accessed at POST http://localhost:8000/companies
router.post('/', function (req, res) {
var name = req.body.name && req.body.name.trim();
var type = req.body.type && req.body.type.trim();
// VALIDATION
if (name === '') {
res.redirect('/companies/create');
return;
}
var model = new Companies({name: name, type: type});
model.save(function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
});
// READ
// accessed at GET http://localhost:8000/companies/:company_id
router.get('/:company_id', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
res.render('companies/read', model);
}
});
});
// UPDATE VIEW
// accessed at GET http://localhost:8000/companies/:company_id/edit
router.get('/:company_id/edit', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
res.render('companies/edit', model);
}
});
});
// UPDATE DATA
// accessed at PUT http://localhost:8000/companies/:company_id
router.put('/:company_id', function(req, res) {
Companies.findById(req.params.company_id, function(err, model) {
if (err) {
res.send(err);
}
else {
model.name = req.body.name;
model.type = req.body.type;
model.save(function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
}
});
});
// DELETE
// accessed at DELETE http://localhost:8000/companies/:company_id
router.delete('/:company_id', function (req, res) {
Companies.remove({ _id: req.params.company_id }, function(err) {
if (err) {
res.send(err);
}
else {
res.redirect('/companies');
}
});
});
};
HTML forms only support GET and POST. XMLHTTPRequest supports PUT and DELETE however, so you may have to go that route OR use something like method-override to allow HTML forms to submit using other HTTP verbs.

Custom callback in Express.js get

I have a get in my app.js
app.get('/api/personnel', api.personnel);
that calls this function as a callback to load some data from mongo:
exports.personnel = function(req, res) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
});
};
That works just fine, but I'd really like to be able to call a callback for testing purposes when the function is complete:
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
callback();
});
callback() is empty when the function is called from the live application and gives me a error:
Error: Can't set headers after they are sent.
How do I go about having a get call my callback?
You can just wrap that function to insert the additional function argument:
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
});
///////////////////////////////////////////////////
var callback = ...;
pp.get('/api/personnel', function(req, res) {
api.personnel(req, res, callback);
});
third arity in Express is always reserved for next() callback (as found in middlewares).
If you want to have "callback" but does not want to mess up with express, let's hack!
exports.personnel = function(req, res, callback) {
var docs;
db.personnel.find(function(err, docs) {
if (err) {
logError(err);
} else {
res.json({
personnel: docs
});
}
if(process.env.NODE_ENV === 'test')
callback();
});
then, when you want to test, export NODE_ENV=test in your shell

Use Async lib in nodejs

Hello guys here is my code:
function get_group(req, res, next) {
var send_result = function(err, group_list) {
[...]
res.send(group_list);
return next();
};
Group.findOne({'_id': req.params._id}, send_result);
}
Now how can I implement the async library (caolan) using async.series and combine the findOne() with send_result, the code as it is look pretty disorganised to me.
EDIT1:
I used this strategy but I am not sure is correct, any suggestion?
function get_group(req, res, next) {
async.waterfall([
function(callback) {
Group.findOne({'_id': req.params._id}, callback);
}
],
function (err, group_list){
res.send(group_list);
return next();
});
}
Any suggestion?
For what they call routes in Express.js you actually almost never need to use the async library. The reason is that routes are actually a sort of control flow them self. They take as many middleware as you want so you can divide your routes into small blocks of code.
For example lets say you want to get one record/document from a database do something with it and then send it as json. Then you can do the following:
var getOne = function(req, res, next){
db.one( 'some id', function(err, data){
if (err){
return next( { type: 'database', error: err } );
};
res.local( 'product', data );
next();
});
};
var transformProduct = function(req, res, next){
var product = res.locals().product;
transform( product, function(data){
res.local('product', data);
next();
});
};
var sendProduct = function(req, res, next){
var product = res.locals().product;
res.json(product);
};
app.get( '/product', getOne, transformProduct, sendProduct );
If you write middleware for your routes like this you'll end up with small building blocks you can easily reuse throughout your application.

Resources