knoll knoll - 4 months ago 19
Node.js Question

Node.js/Express - Routing More Than One Form Post

I'm working on webpage that has two separate forms on it, with two separate form actions. I can get one form to work, but I can't get both to work. I've got post route router.post('/direct-user',...) and post route router.post('/other-user', ...), if I change one of those to just router.post('/',...) then it works just fine.

I suspect there's something wrong in my app.js route declarations, but I can't figure it out.

Any guidance would be super awesome.

My app structure looks like this:

/project
/routes
index.js
requser.js
/views
error.hbs
index.hbs
layout.hbs
requser.hbs
app.js
package.json


And here's my main app file which has my module imports, route locations, and error handling.
app.js


// Module imports //
var express = require('express');
var bodyParser = require('body-parser');
var cookieParser = require('cookie-parser');
var morgan = require('morgan');
var path = require('path');
var app = express();

app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
app.use(morgan('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(validator());
app.use(express.static(path.join(__dirname, 'public')));


// Routes and views //
app.use('/', require('./routes/index'));
app.use('/user/:id', require('./routes/user'));
app.use('/user-update', require('./routes/user'));
app.use('/requser', require('./routes/requser'));
app.use('/direct-user', require('./routes/requser'));
app.use('/other-user', require('./routes/requser'));


// Catch 404 and forward to error handler //
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});

// Development error handler; will print stacktrace //
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}

// Production error handler; no stacktraces leaked to user //
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});

module.exports = app;


Here's my requser file which includes one get route to load the empty form, and two post routes to handle the input from one of the two forms.
requser.js


// Module imports //
var express = require('express');
var router = express.Router();


// GET request user form //
router.get('/', function(req, res, next) {
res.render('requser', {
title: 'User Request'
});
});


// POST /direct-user //
router.post('/direct-user', function(req, res) {
// Validate form contents
// ...

// Assuming all is well
console.log('Direct user requested');
res.send('cool');
});

// POST other-user //
router.post('/other-user', function(req, res) {
// Validate form contents
// ...

// Assuming all is well
console.log('Other user requested');
res.send('cool');
});

module.exports = router;


And lastly, my form view/template.
requser.hbs

<div class="container">
<h1>User Request</h1>

<!-- Start of direct user creation form //////////////////////////////// -->
<form method="post" action="/direct-user">
<!-- First name, last name -->
<!-- ... -->

<!-- Submit button -->
<div class="row">
<div class="col-md-11">
<div class="form-group">
<button type="submit" class="btn btn-custom">Submit</button>
</div>
</div>
</div> <!-- End row -->
</form> <!-- End form -->


<!-- Start of other user creation form //////////////////////////////// -->
<form method="post" action="/other-user">
<!-- First name, last name -->
<!-- ... -->

<!-- Submit button -->
<div class="row">
<div class="col-md-11">
<div class="form-group">
<button type="submit" class="btn btn-custom">Submit</button>
</div>
</div>
</div>
</div> <!-- End container -->

Answer

You are using the routing middleware in an incorrect way.

app.use('/user/:id', require('./routes/user'));
app.use('/user-update', require('./routes/user'));
app.use('/requser', require('./routes/requser'));
app.use('/direct-user', require('./routes/requser'));
app.use('/other-user', require('./routes/requser'));

These lines are the problematic ones.

Let's take one of these as an example, the third one, as that one by itself is enough to take care of the /direct-user and /other-user endpoints.

What that line tells express to do is:

When a request hits the server whose path starts with /requser, pass that request to the requser router middleware and it will handle the rest.

Let's say that your request is to the path /requser/direct-user. That request will be passed to the requser middleware and that middleware will than match the remaining part (/direct-user) and correctly invoke the relevant callback.

Without knowing where your form posts the data, I can't help you further. But you should check that both forms post their data to /requser/direct-user and /requser/other-user, respectively and it should work.

Comments