I want to separate routes from controller.
I tried this approach:
routes/index.js
var express = require('express');
var router = express.Router();
var wordMapperController = require('../controller/wordmapper');
router.get('/', wordMapperController());
module.exports = router;
controller/wordmapper.js
var __construct = function(req, res, next) {
res.render('index', { title: 'Word Mapping for Sanskrit-Indonesian in BG' });
next();
}
module.exports = __construct;
When I start the res is undefined, and prevent the app to be launched.
How does I handle this? How is it app.use and handle router middleware being passed?
The reason why you're getting res is undefined is because you're calling the wordMapperController function and then passing what it returns (in this case undefined, since you don't return anything) as the callback to the router.get method...
This is what you should be doing instead:
routes/index.js
router.get('/', wordMapperController);
Also, there's no reason to call next() in your controller/wordmapper.js file...
From the express.js documentation:
If the current middleware function does not end the request-response cycle, it must call next() to pass control to the next middleware function. Otherwise, the request will be left hanging.
In your case, you're ending your request-response cycle with the res.render method invocation, therefore you should only be doing this:
controller/wordmapper.js
var __construct = function(req, res, next) {
res.render('index', {
title: 'Word Mapping for Sanskrit-Indonesian in BG'
});
}
You are doing good. But small changes will make your application looks perfect. Find them below.
Change the line "router.get('/', wordMapperController())" to
"router.get('/', wordMapperController)" - because when hits the route "/", it
will calls the middle ware function in the controller by passing request, response
and next as parameters;
If you want to render a template, you have to set the template engine server file -
for eg: app.set('view engine', 'pug') (if it is a .pug file);
Let me know if you get any issues while doing the above.
For reference, You can go through this link - https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes
Thank you.
Related
the code below works:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', express.static("./public"));
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
But if I change the app.use like this:
var express = require('express');
var path = require('path');
var app = express();
app.use('/public', function(){express.static("./public")});
// browser error "cannot GET /
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Why? The server doesn't seem to catch any errors
express.static() returns a middleware function when you call it. You have to pass that specific returned function to app.use(). You don't just call express.static() on every request. You call it once, get the returned function and register that as middleware and app.use() will then call that middleware function on every request.
When you do it the correct way like this:
app.use('/public', express.static("./public"));
It's like doing this:
const fn = express.static("./public");
app.use('/public', fn);
or even like this:
const fn = express.static("./public");
app.use('/public', function(req, res, next) {
fn(req, res, next);
});
Hopefully you can see that this code:
app.use('/public', function(){express.static("./public")});
does not do the same thing as any of the correct solutions. This calls express.static() in every request and never calls the returned function that does the actual work for a given request.
Think of express.static("./public") like a factory function. It creates a middleware function that you then pass to app.use() or call yourself with req, res and next as the arguments.
Why? The server doesn't seem to catch any errors
Executing app.use('/public', function(){express.static("./public")}); is not what you want, but it also doesn't create an error. All it does is create a new middleware function (which you ignore) on every single request. It also never calls next to let any other request handlers handle the request so your server would get stuck on every request, but it never actually causes a visible error.
It essentially becomes functionally equivalent to this:
app.use('/public', function(req, res, next) {
// do nothing, just causes the request to get stuck since
// the request is not handled (no response is sent)
// and next is never called
});
The request is never handled and never calls next to advance to other route handlers so the request just gets stuck and will eventually time out.
You can try with:
app.use(express.static(path.resolve(__dirname, './public'), { maxAge: '1d' }));
I am using keystone and I have productDetail route in which I can add variables in res.locals to be used in templates. Is there a way I can use res.locals (of route file) in middleware.js file? As right now middleware is executing before route, I want route file to be executed first.
This is where middleware is executing in index.js file
keystone.pre('routes', middleware.initLocals);
And after that we have
exports = module.exports = function(app) {
// Views
app.get('/', routes.views.index);
app.get('/product-detail/:product', routes.views.productDetails);
}
I'm not sure if I got your question but this might help. You can run as many custom middleware you want after the middleware.initLocals (which apparently runs first). In your routes/middleware.js file, you can have, for example, two middleware:
exports.middleware0 = function (req, res, next) {
// Do some stuff
next();
};
exports.middleware1 = function (req, res, next) {
// Do some other stuff
next();
};
Then, inside your routes/index.js you can chain middleware together:
//...
var middleware = require('./middleware');
//...
exports = module.exports = function (app) {
// Use the middleware0 and middleware1:
app.get('/product-detail/:product', [middleware.middleware0, middleware.middleware1], routes.views.productDetails);
};
I'm using node and express to create a rest api. I followed a tutorial where all the routes and its logic are saved in a routes.js file like this:
SERVER JS:
var express = require('express');
var app = express();
(...)
require('./app/routes.js')(app, port, express);
ROUTES.JS
module.exports = function(app, port, express) {
var apiRoutes = express.Router();
(...)
//Sample route
apiRoutes.get('/userfiles', function(req, res) {
UserFile.find({ owner: req.decoded.user.email }, function(err, filesList) {
if (err)
return done(err);
res.json({ success: true, files: filesList });
});
});
My problem is twofold:
1 - Routes can easily contain code thats 150 lines long, some of them far longer. It doesn't feel clean to have route declarations and the logic grouped together. Is it a good practice to do something like this instead?
apiRoutes.post('/randomRoute', function(req, res) {
return res.json(functionThatContainsTheActualCode(req));
});
(and then have an functionThatContainsTheActualCode function with all the logic in a different file).
2 - I have middleware that applies to some functions (for example, some routes are only accessible for logged in users and those routes go through an authentication middleware). Currently way I do it is declaring public routes before the middleware declaration and private routes after, which feels incredibly hacky. How can I separate public and private routes (and the middleware itself) in different files?
Problem 1:
We need to go deeper.
Change the route file to just require the actual router logic.
routes.js
// where app = express();
module.exports = (app) => {
// index.js happens to be a file exporting the router.
app.use('/', require('./index'));
// this is basically the idea. Create a separate file for the actual logic.
app.use('/route', require('.path/to/file'));
};
and in file.js
const express = require('express'),
router = express.Router();
router.verb('/path/', (req, res, next) => {
// do whatever
});
// this is required
module.exports = router;
Problem 2:
Middleware is basically a function taking in request, response, next as 3 params, doing something with the request and either sending out a response or moving on to the next middleware. That's why you need to call next if you want to move to next middleware in the chain.
Now all you need is a file that exports a function which takes request, response, next as params.
// lets call this auth.js
module.exports = function(req, res, next) {
// do logic
if () {
return res.send(); // or res.somethingThatSendsOutAHttpResponse()
}
// next middelware
next();
};
Since express routes are also middlewares, (mind blown), you can mount them top down.
To authenticate a route, just put the auth.js middleware on top of that route.
router.get('/', require('./auth'));
router.get('/', require('./log'));
router.get('/', (req, res, next) => {
// yolo
});
Now since this is web dev, you still got problems.
Now all your boring database queries are scattered everywhere.
Fear not, you can solve it, by, guess, creating another file.
apiRoutes.get('/userfiles', function(req, res) {
const userFile = require('/path/to/model/with/userfile/methods/exported/out');
// do something with userFile's methods
});
Say I have some routes (I have a lot more, but this should explain):
router.post('/post');
router.get('/post/:id');
router.get('/posts/:page?');
router.get('/search');
For the /post ones I know I could do something like
app.use('/post', postRoutes)
Where postRoutes is the actual post routes in another file. However, I'd like to group all post related routes into a postRoutes component (so /post and /posts), search into a search component and so on. Is there a way to do something like
router.use(postRoutes); // includes routes 1-3 above
router.use(searchRoutes); // only the 4th route above
And so on? That would let me keep the top level file much cleaner.
Yes it is simple. You can even make more nesting levels. I think it is good to separate routes, especially when you have dozens of routes.
in your first file (server.js)
app.use(require("./allpost"));
app.use(require("./allqueries"));
in allpost.js
var express = require('express');
var router = new express.Router();
router.post('/post', function (req, res) {
//your code
});
router.get('/post/:id', function (req, res) {
//your code
});
router.get('/posts/:page?', function (req, res) {
//your code
});
when you want more nesting
router.use(require("./deeper"));
or when you want use path part
router.use("/post2/", require("./messages/private"));
module.exports = router;
You could do that by creating a special route file. Here's an example of such file
module.exports = (function() {
var express = require('express');
var router = express.Router();
router.get("/:id", function (request, response, next) {
request.body.id = request.params["id"];
// Do something ...
});
router.post("/someRoute", function (request, response, next) {
// Do something ...
});
// And so on ...
return router;
})();
Next, in you server.js file, include it like this
app.use('/post', require('./routes/postRoutes'));
The problem was I was thinking about this wrong. First off, don't use singular and plural. It makes it a headache and also makes it hard for people to remember the API.
Once I used all plural I had a setup like this in my index.js file:
// The API routes all start with /api and we pass app here so we can have some
// sub routes inside of api
app.use('/api', require('./app/api')(app));
And then in my api/index.js
var express = require('express');
var router = express.Router({ mergeParams: true });
var routeInit = function (app) {
app.use('sessions', require('./sessions')(router));
app.use('users', require('./users')(router));
return router;
};
module.exports = routeInit;
You can see that I'm passing the router manually each time. Then finally:
var routeInit = function (router) {
router.post('/blah', function (req, res, next) {
// Do stuff
});
return router;
};
module.exports = routeInit;
This allowed me to nest routes infinitely deep.
I am new to the whole Node.js thing, so I am still trying to get the hang of how things "connect".
I am trying to use the express-form validation. As per the docs you can do
app.post( '/user', // Route
form( // Form filter and validation middleware
filter("username").trim()
),
// Express request-handler gets filtered and validated data
function(req, res){
if (!req.form.isValid) {
// Handle errors
console.log(req.form.errors);
} else {
// Or, use filtered form data from the form object:
console.log("Username:", req.form.username);
}
}
);
In App.js. However if I put something like app.get('/user', user.index); I can put the controller code in a separate file. I would like to do the same with the validation middleware (or put the validation code in the controller) to make the App.js file easier to overview once I start adding more pages.
Is there a way to accomplish this?
Basically I would like to put something like app.get('/user', validation.user, user.index);
This is how you define your routes:
routes.js:
module.exports = function(app){
app.get("route1", function(req,res){...})
app.get("route2", function(req,res){...})
}
This is how you define your middlewares:
middlewares.js:
module.exports = {
formHandler: function(req, res, next){...}
}
app.js:
// Add your middlewares:
middlewares = require("middlewares");
app.use(middlewares.formHandler);
app.use(middlewares...);
// Initialize your routes:
require("routes")(app)
Another way would be to use your middleware per route:
routes.js:
middlewares = require("middlewares")
module.exports = function(app){
app.get("route1", middlewares.formHandler, function(req,res){...})
app.get("route2", function(req,res){...})
}
I hope I answer your questions.
You can put middleware functions into a separate module in the exact same way as you do for controller functions. It's just an exported function with the appropriate set of parameters.
So if you had a validation.js file, you could add your user validation method as:
exports.user = function (req, res, next) {
... // validate req and call next when done
};