Defining root and error routes in NodeJs/Express - node.js

I defined some routes for my application. Like
app.get('/page1', function (req, res) {
res.render('page1');
});
app.get('/page2', function (req, res) {
res.render('page2');
});
and if the route is missing or wrong, the application should always redirect to another page. I want to define a root route:
app.get('/', function (req, res) {
res.render('notFound'); // redirect to a 404 template
});
and what do I have to define to cover all the error or missing pages?
When having '/page1/abcdefgh' and '/fooBar' both routes should redirect to the res.render('notFound'); template.

To handle a 404 place a * route-handler below all pre-defined routes. So if none of your predefined routes will match (like /page1 or /page2), the * will get triggered.
// Will match /page1
app.get('/page1', function (req, res) {
res.render('page1');
});
// Will match /page2
app.get('/page2', function (req, res) {
res.render('page2');
});
// Will be triggered if nothing above got a match
app.get('*', function (req, res) {
res.render('notFound'); // redirect to a 404 template
});

Related

Express.js serve static folder at specific url only

I have an existing express app I'm using for an API but I also want to deliver a folder with an HTML file and some images/css/js. I can get it to serve the HTML page but it does so at / while I only want it served at /manual. Here is my stripped down code with just express.static, my / route and the catch all redirect to /
const app = express();
app.use(express.static('manual'));
app.get('/', (req, res) => {
res.status(403);
res.send('Access denied.');
return;
});
app.get('*', (req, res) => {
res.redirect(301, '/');
return;
});
What currently happens: Going to mysite.com/manual redirects to mysite.com/ which serves the index.html in the manual folder.
What I want to happen: Going to mysite.com/manual serves the index.html in the manual folder. And going to mysite.com/ throws a 403 status code.
Middleware/handlers are applied in the order you declare them, so you just need to change the order
const app = express();
app.get('/', (req, res) => {
res.status(403);
res.send('Access denied.');
return;
});
// adding a first parameter lets you apply the middleware to a route
app.use('/manual', express.static('manual'));
app.get('*', (req, res) => {
res.redirect(301, '/');
return;
});

How do I automatically return a 404 when a GET path doesn't exist?

I am using NodeJS, Express and Handlebars (template engine) to build a web application. Currently I'm trying to automatically redirect users whenever they enter an URL that does not exist (or whenever they might not have access to it).
The following returns the index page:
router.get('/', (req, res) => {
res.render('index/index');
});
But how do I make something like this:
router.get('/:ThisCouldBeAnything', (req, res) => {
res.render('errors/404');
});
The following example is from Github:
Say that I enter this URL:
https://github.com/thispagedoesnotexist
It automatically returns a 404. How do I implement this in my application?
Thanks in advance.
Use a middleware just after all route handlers to catch non existing routes:
app.get('/some/route', function (req, res) {
...
});
app.post('/some/other/route', function (req, res) {
...
});
...
// middleware to catch non-existing routes
app.use( function(req, res, next) {
// you can do what ever you want here
// for example rendering a page with '404 Not Found'
res.status(404)
res.render('error', { error: 'Not Found'});
});
After all your other routes you can add:
app.get('*', (req, res) => {
res.render('errors/404');
});
Alternately, you can use a middleware function after all your other middleware and routes.
app.use((req, res) => {
res.render('errors/404');
});
So you might end up with something that looks like:
//body-parser, cookie-parser, and other middleware etc up here
//routes
app.get('/route1', (req, res) => {
res.render('route1');
});
app.get('/route2', (req, res) => {
res.render('route2');
});
//404 handling as absolute last thing
//You can use middleware
app.use((req, res) => {
res.render('errors/404');
});
//Or a catch-all route
app.get('*', (req, res) => {
res.render('errors/404');
});
I see that you have express tagged. All you have to do is include a default handler that includes
res.status(404).render('404template')
For example
app.get('*', (req, res,next) => {
res.status(404).render('error.ejs')
});

express.static handling root url request

express.static is handling the root url request.
e.g. I want to do a redirect in express from https://example.com to https://example.com/dashboard.
Check the cases below, first one works, second does not. I expect the second to work too. Anyone knows why?
Case 1 (works)
app.get('/', (req, res, next) => {
res.redirect('/dashboard');
})
app.use(express.static(path.join(__dirname, 'dist')))
app.get('/dashboard', (req, res, next) => {
//do stuff
})
Case 2 (does not work for me)
app.use(express.static(path.join(__dirname, 'dist')))
//request doesn't come here
app.get('/', (req, res, next) => {
res.redirect('/dashboard')
})
app.get('/dashboard', (req, res, next) => {
//do some stuff
})
That would happen if there's a file dist/index.html, because that's what express.static() would look for when retrieving a directory (in this case /).
You can turn that behaviour off like this:
app.use(express.static(path.join(__dirname, 'dist'), { index : false }))
Documented here: http://expressjs.com/en/4x/api.html#express.static

Passing extra parameters to route handlers in Express

I'm relatively new to Express, and I'm looking for a way to make routes more reusable. In my app, I will have quite a few routes that can be passed to a generic handler, but will have different templates.
Example:
app.get('/about', function(req, res) {
res.render('about.html');
});
app.get('/', function(req, res) {
res.render('home.html');
});
While this example is contrite, I have 30+ such routes. What I would like to be able to do is something like this:
app.get('/about', generic.render('about.html'));
or otherwise somehow pass the template name to the function that returns res.render Is this possible in Express? All of my attempts to work around this result in variables being undefined.
I would prefer to not do something like this, tightly coupling my route parameters and template names:
app.get('/:template', function(req, res) {
res.render(req.params.template + '.html');
});
You could just make a a simple middleware that does this for you. Example:
function simpleRender(file, opts) {
opts || (opts = {});
return function(req, res) {
res.render(file, opts);
};
}
Then just use it like:
app.get('/about', simpleRender('about.html'));
app.get('/', simpleRender('home.html'));
This is how I do it:
const handler = (req, res, template) => {
res.render(template)
}
app.get('/about', (req, res) => {
handler(req, res, 'about.html')
})
This is a best practice for me
app.get('/:template',(req, res, next) => {
res.locals = `${template}.html`;
next();
},
renderMethod
);
function renderMethod(req, res){
res.render(res.locals)
}

Express - public directory divided for authorized/unauthorized users

I have an app written in express.js and I'm trying to divide this application to 2 sections:
one for unauthorized users (with routes only to / - landing page, /login and /* - error404)
and second (routes will be: / - landing page, /app/* - angular SPA which will handle routing on its own)
Express is also configured to take static files from /unauth/public/
And I want to add second static folder for request from authorized routes - /auth/public
which goes to /app/*
My route config looks like this:
var authRoutes = express.Router();
var unauthRoutes = express.Router();
authRoutes.get('/app/*', function(req, res, next) {
if(!req.isAuthenticated())
return res.redirect("/login/");
res.send("AUTHORIZED");
});
unauthRoutes.get('/', function(req, res, next) {
res.send("LANDING PAGE");
});
unauthRoutes.get('/login/', function(req, res, next) {
if(req.isAuthenticated())
return res.redirect("/app/");
res.send("LOGIN PAGE");
});
unauthRoutes.get('/registration/', function(req, res, next) {
if(req.isAuthenticated())
return res.redirect("/app/");
res.send("REGISTRATION PAGE");
});
unauthRoutes.get('/*', function(req, res, next) {
res.send("ERROR 404");
});
app.use('/', authRoutes);
app.use('/', unauthRoutes);
I tried to modify req.url and call another static oruter express.static('auth/public') based on this:
Using express.static middleware in an authorized route
But I don't know, how to handle route app.get('/auth/*', ...) - previous modification will replace url and this route will never be called..
You could try something like this:
// Create your static middlewares
var unauthStatic = express.static('unauth/public');
var authStatic = express.static('auth/public');
// This goes in place of where you would normally load your static middleware
app.use(function(req, res, next) {
if (req.isAuthenticated()) {
authStatic(req, res, next);
} else {
unauthStatic(req, res, next);
}
});
edit:
if you want authenticated users to be able to access files from both the auth and unauth directories, you can make two calls to app.use, like this:
app.use(unauthStatic);
app.use(function(req, res, next) {
if (! req.isAuthenticated()) {
return next();
}
authStatic(req, res, next);
});
Remember that express uses middleware in a stack, meaning to serve a given request, all registered middleware is used in the order it's used. Once a bit of middleware calls req.send, no further middleware gets executed. Anyway, try something like this:
function Authorization(req, res, next) {
if(!req.isAuthenticated())
return res.redirect("/login");
next();
}
var AnonRouter = express.Router()
// GET /style.css will request /unauth/public/style.css
.use(express.static('unauth/public'))
.get('/', function (req, res) { })
.get('/login', function (req, res) { });
var AuthRouter = express.Router()
.use(Authorization)
// GET /app/style.css will request /auth/public/style.css
.use(express.static('auth/public'))
.get('*', function (req, res, next) {
// Handle reqs for non-static files
});
app.use('/', AnonRouter);
app.use('/app', AuthRouter);
app.get('*', function (req, res) {
res.status(404).send('404!');
});
But I don't know, how to handle route app.get('/auth/*', ...) - previous modification will replace url and this route will never be called..
This statement makes me think that you are trying to somehow handle the request after express's static middleware has been called. This is not possible: the static middleware serves static files and you cannot execute additional logic after it does so, but you can run stuff before! Note that in my code, the Authorization middleware will run before the static file is sent.

Resources