Distinguish Between Request Parameters in the same position? - node.js

Is there a way to distinguish between request parameters in the same position in expressjs?
E.g., is there a way to have:
router.get('/pages/:id', function(req,res){
var id=req.params.id;
api.getPagebyID(id, function(err,pageData){
if (err) console.log(err);
console.log(pageData);
});
});
And to have:
router.get('/pages/:name', function(req,res){
var name=req.params.name;
api.getPagebyName(name, function(err,pageData){
if (err) console.log(err);
console.log(pageData);
});
});

You can certainly set multiple middlewares for a particular pattern, but it's up to you to decide when to skip a middleware (with next). After a response is sent, no further middlewares are executed.
router.get('/pages/:id', function(req, res, next){
var id=req.params.id;
api.getPagebyID(id, function(err,pageData){
console.log(pageData);
if (err){
console.log(err);
if(err.error === 'not_found'){
// No id. Try name:
next();
} else {
// Actual error:
res.status(500).send();
}
}
});
});
router.get('/pages/:name', function(req,res){
var name=req.params.name;
api.getPagebyName(name, function(err,pageData){
if (err) console.log(err);
console.log(pageData);
});
});

If ID is a number, you can use regex to only match numbers:
router.get('/user/:id([0-9]+)', function(req, res){
res.send('user ' + req.params.id);
});
router.get('/range/:range(\\w+\.\.\\w+)', function(req, res){
var range = req.params.range.split('..');
res.send('from ' + range[0] + ' to ' + range[1]);
});
Check out the docs here: http://expressjs.com/4x/api.html#router.param

Related

Nodejs Rest API with mongoose and mongoDB

I have this rest API on nodejs as follows
router.route('/api/Customers')
.post(function(req, res) {
var Customer = new Customer();
Customer.name = req.body.name;
Customer.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Customer created!' });
});
})
.get(function(req, res) {
Customer.find(function(err, Customers) {
if (err)
res.send(err);
res.json(Customers);
});
});
router.route('/api/Customers/:Customer_id')
.get(function(req, res) {
Customer.findById(req.params.Customer_id, function(err, Customer) {
if (err)
res.send(err);
res.json(Customer);
});
})
.put(function(req, res) {
Customer.findById(req.params.Customer_id, function(err, Customer) {
if (err)
res.send(err);
Customer.name = req.body.name;
Customer.save(function(err) {
if (err)
res.send(err);
res.json({ message: 'Customer updated!' });
});
});
})
.delete(function(req, res) {
Customer.remove({
_id: req.params.Customer_id
}, function(err, Customer) {
if (err)
res.send(err);
res.json({ message: 'Successfully deleted' });
});
});
How can I create endpoints for specific fields ? For example if I want to GET results for CustomerName, CustomerZip, etc .. Do I have to create separate end points for each field?
Are you using express.js as framework? In this case you can put optional params in your route, for example:
router.route('/api/Customers/:Customer_id?')
.post(function(req, res) {
...
})
.get(function(req, res) {
...
});
});
in this way :Customer_id will be optional and you can manage logic inside your route.
This is a working example:
app.route('/test/:param1?/:param2?')
.get( function(req, res, next) {
res.json({
'param1' : req.params.param1,
'param2' : req.params.param2
});
});
app.listen(8080);
this route supports:
/test
/test/1
/test/1/2
inside response you can see value of this params, I don't know how pass only param2 without param1.

Error: Can't set headers after they are sent nodejs

When I post the new event, it is created and the sort function works properly as well but when I call the search function, I want it to compare it with both name and location but it doesn't compare with location. Is there any way to check both? Also after sorting or search when I want to create a new event, it gives me the below error. I am new to this. Help me with both the errors.
server.js
var express= require('express');
var bodyParser= require('body-parser');
var morgan = require('morgan');
var config=require('./config');
var app= express();
var mongoose=require('mongoose');
var lodash= require('lodash');
var underscore= require('underscore');
//var User=require('./database/user')
mongoose.connect('mongodb://localhost:27017/db',function(err){
if(err){
console.log(err);
}
else{
console.log("connected!");
}
});
//res.json({message:" " })
app.use(bodyParser.urlencoded({extended: true })); //if false then parse only strings
app.use(bodyParser.json());
app.use(morgan('dev'));//log all the requests to the console
var api=require('./app/routes/api')(app,express,underscore,lodash);
app.use('/api',api);
app.get('*',function(req,res){
// res.sendFile(__dirname + '/public/views/index.html');
}); // * means any route
app.listen(config.port,function(err){
if(err){
console.log(err);
}
else{
console.log("The server is running");
}
});
api.js
var User= require('../models/user');
var Event=require('../models/event');
var config=require('../../config');
var secret=config.secretKey;
module.exports=function(app,express,underscore,lodash) {
var api = express.Router();
// app.use()
api.post('/signup', function (req, res) {
var user = new User({
name: req.body.name,
username: req.body.username,
password: req.body.password
});
user.save(function (err) {
if (err) {
res.send(err);
return;
}
res.json({
message: 'User created!'
});
});
});
api.get('/users', function (req, res) {
User.find({}, function (err, users) {
if (err) {
res.send(err);
return;
}
res.json(users);
});
});
/* api.get('search',function(req,res){
search: req.body.search;
if(search==)
});*/
api.post('/eventfeed', function (req, res) {
var event = new Event({
name: req.body.name,
location: req.body.location,
description: req.body.description,
price: req.body.price,
rating: req.body.rating
});
event.save(function (err) {
if (err) {
res.send(err);
return;
}
res.json({
message: 'Event created!'
});
});
});
api.get('/event', function (req, res) {
Event.find({}, function (err, event) {
if (err) {
res.send(err);
return;
}
res.json(event);
});
});
api.get('/sortby_price', function (req, res) {
Event.find({}, function (err, events) {
if (err) {
res.send(err);
return;
}
var ascending = true;//change to false for descending
events.sort(function (a, b) {
return (a.price - b.price) * (ascending ? 1 : -1);
});
res.json(events);
});
});
api.get('/sortby_rating', function (req, res){
Event.find({}, function (err, events) {
if (err) {
res.send(err);
return;
}
var ascending = true;//change to false for descending
events.sort(function (a, b) {
return (a.rating - b.rating) * (ascending ? 1 : -1);
});
res.json(events);
});
});
api.post('/search', function (req, res) {
Event.find({'name':req.body.name},function (err, events) {
if (err)
return res.json(err);
else
res.json(events);
});
Event.find({'location':req.body.name},function (err, events) {
if (err)
return res.json(err);
else
res.json(events);
console.log("name is" + req.body.name);
});
});
return api;
}
error
http_outgoing.js:335
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:335:11)
at ServerResponse.header (c:\Users\MY LAPY\WebstormProjects\Main\node_modules\express\lib\response.js:718:10)
at ServerResponse.send (c:\Users\MY LAPY\WebstormProjects\Main\node_modules\express\lib\response.js:163:12)
at ServerResponse.json (c:\Users\MY LAPY\WebstormProjects\Main\node_modules\express\lib\response.js:249:15)
at Query.<anonymous> (c:\Users\MY LAPY\WebstormProjects\Main\app\routes\api.js:209:25)
at c:\Users\MY LAPY\WebstormProjects\Main\node_modules\mongoose\node_modules\kareem\index.js:177:19
at c:\Users\MY LAPY\WebstormProjects\Main\node_modules\mongoose\node_modules\kareem\index.js:109:16
at process._tickCallback (node.js:355:11)
In your /api/search route, you are performing two Event.find()s in parallel and inside the callback for each of those, you're responding to the same http request.
So you need to either:
Have a third callback that is called only when both Event.find()s have completed, so you respond to the request only once there, OR
Perform the Event.find()s sequentially by placing one inside the callback of the other and only respond to the request inside the inner-most callback, OR
Only perform one Event.find() by using $or to check either field. For example:
api.post('/search', function (req, res) {
Event.find({
$or: [ {'name': req.body.name}, {'location': req.body.name} ]
}, function (err, events) {
if (err)
return res.json(err);
else
res.json(events);
});
});

Express Router CRUD API. Cannot DELETE

Well, I'm reading the MEAN Machine book and following it's examples. I'm trying to figure out what's wrong with my code so it won't make any DELETE request. GET, PUT and POST works as should.
I have this code on my server.js:
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'X-Requested-With, content-type, Authorization');
next();
});
var apiRouter = express.Router();
apiRouter.route('/users/:user_id')
.get( function (req, res) {
User.findById( req.params.user_id, function (err, user) {
if (err) res.send (err);
res.json(user);
});
})
.put( function (req, res) {
User.findById(req.params.user_id, function (err, user) {
if (err) res.send(err);
if (req.body.name) user.name = req.body.name;
if (req.body.username) user.username = req.body.username;
if (req.body.password) user.password = req.body.password;
user.save( function (err){
if (err) send (err);
res.json({message: 'User updated'});
});
})
.delete( function (req, res) {
User.remove({
_id: req.params.user_id
}, function (err, user) {
if (err) return res.send(err);
res.json({ message: 'Deleted' });
});
});
});
I have a set of users the Modulus MongoDB database and, when I try to use POSTMAN with localhost:8080/api/users/5610e5576d827dc41fb8e6e, POSTMAN says
Cannot DELETE /api/users/5610e5576d827dc41fb8e6e
while my Node server with Morgan says
DELETE /api/users/5610e5576d827dc41fb8e6e 404
Why I'm getting a 404? What Am I doing wrong?
Full code
You've placed closing brackets of put() in wrong place. So you're defining your delete router inside the put() router:
This is your code after proper indentation:
.put( function (req, res) {
User.findById(req.params.user_id, function (err, user) {
if (err) res.send(err);
if (req.body.name) user.name = req.body.name;
if (req.body.username) user.username = req.body.username;
if (req.body.password) user.password = req.body.password;
user.save( function (err){
if (err) send (err);
res.json({message: 'User updated'});
});
})
.delete( function (req, res) { // <===== defined inside 'put',
User.remove({
_id: req.params.user_id
}, function (err, user) {
if (err) return res.send(err);
res.json({ message: 'Deleted' });
});
});
})
So, just move the delete router outside of put router callback

Can't assign req.session.user when is called fs.mkdir

This is the code of the app.post that calls fs.mkdir by the function that I made, newdir:
app.post('/register', express.bodyParser(), function (req, res, next){
var newu = new UserModel({});
newu.user = req.body.nuser;
newu.pass = req.body.npass;
newu.mail = req.body.nmail;
UserModel.find({ user: req.body.user }, function (err, user){
if (user.lenght == 1) {
res.redirect('/');
}
else {
newdir(req.body.nuser);
next()
if (err) throw err;
newu.save(function (err, newu){
req.session.user = newu.user;
res.redirect('/home')
});
}
});
});
This is the code of newdir:
function newdir (username){
var pathu = __dirname + '/users/' + username;
fs.mkdir(pathu, function (err){
if (err) throw err;
});
}
An this is the code of /home:
app.get('/home', function (req, res){
console.log(req.session.user);
res.send('Welcome ' + req.session.user + '!');
});
I can assign a req.session.user in all app.post/get that I want, for example when I verify the user with this, I can assign the req.session.user correctly:
app.post('/verify', express.bodyParser(), function (req, res){
UserModel.find({ user: req.body.user }, function (err, user){
if (user[0] == undefined) {
res.redirect('/');
}
else{
if (user[0].pass == req.body.pass) {
req.session.user = user[0].user;
res.redirect('/home');
}
else{
res.redirect('/');
}
}
if (err) throw err;
});
});
But when I try to assign req.session.user in the same app.post where's it's called fs.mkdir, always req.session.user is undefined. Maybe I should create a module that makes the fs.mkdir call? I don't know what to do!
The problem is resolved when fs.mkdir is called in other module, very simple :D

calling functions and passing callback with express.js

What's the proper way to use custom callbacks with express.js functions?
Here's an example:
//routes/reset.js
user.save(function(err){
if ( err ) return next(err);
reset.send_reset_email(req, res, user, function(req, res){
req.flash('info', 'Check your email for a link to reset your password.');
res.redirect('/');
});
});
What signature should I use for reset.send_reset_email for this to work correctly?
This is what I have:
exports.send_reset_email = function(req, res, user, next){
//send email
transport.sendMail(options, function(err, responseStatus) {
if (err) {
console.log(err);
} else {
next(req, res);
//do I need to explicitly pass req, res here?
//is next() reserved word here?
}
});
});
Do I need to explicitly pass req, res here?
is next() reserved word here?
next() accepts an error or another route and is usualy called to continue with the next middleware.
in your send_reset_email function your next() isn't express's next() because you pass in function(req,res) and not next, pass in your own callback instead to handle the outcome of your sendmail function.
user.save(function(err){
if (err) return next(err) // if thats express's next()
reset.send_reset_email(req, res, user, function(err, data){
if(err) {
// send err msg
} else {
req.flash('info', 'Check your email for a link to reset your password.');
res.redirect('/');
}
});
});
xports.send_reset_email = function(req, res, user, cb){
//send email
transport.sendMail(options, function(err, responseStatus) {
if (err) return cb(err)
cb(null,responseStatus)
})
})

Resources