27

I have code like this that will render a jade template without a route defined. Think of this like the express.static but it calls res.render with the url.

app.use(function (req, res, next) {
    try {
        res.render(req.url.substring(1), { title: "No Controller", user: req.session.user });
    } catch (err) {
        console.log(err)
        next();
    }
});

The problem is that res.render() isn't throwing an error. Instead it is rendering an error page. Is there a way to detect a missing template or any rendering errors?

respectTheCode
  • 42,348
  • 18
  • 73
  • 86

4 Answers4

49

A better way to do it, instead of requiring fs and having another callback, would be to use render's callback :

res.render(my_page_im_not_sure_it_exists, {}, function(err, html) {
    if(err) {
        res.redirect('/404'); // File doesn't exist
    } else {
        res.send(html);
    }
});
respectTheCode
  • 42,348
  • 18
  • 73
  • 86
Augustin Riedinger
  • 20,909
  • 29
  • 133
  • 206
  • 4
    Great find. Its only in 3.x docs but it works in 2.x as well. – respectTheCode Mar 29 '13 at 13:05
  • 1
    Updated answer to use `res.send` instead of `res.end`. 4.x documentation [specifically states](http://expressjs.com/api.html#res.end) "If you need to respond with data, instead use methods such as res.send()" – Codebling Jul 20 '15 at 00:45
  • 1
    I thought this would generate a 404 if there was an error processing the template, but it doesn't seem to. Anyone care to explain why it does not? – Codebling Jul 20 '15 at 00:46
  • A `404` code is what **your server** wants to reply to a request to tell the querying browser [conventionnaly](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) that the page was not found. At this step, you **are** the server, and you are free to reply with whatever you want. If you want to send a 404 error instead of redirecting the the `/404` url, the correct way to do this is [here](http://stackoverflow.com/questions/8393275/how-to-programmatically-send-a-404-response-with-express-node). – Augustin Riedinger Jul 20 '15 at 08:59
  • What does the second argument in 'render' indicate? I am talking about the "{}" after "my_page_im_not_sure_it_exists" – Sebastian Nielsen Mar 23 '19 at 14:23
  • Options I guess. Unable to tell you which without the docs though. – Augustin Riedinger Mar 25 '19 at 08:47
  • @SebastianNielsen its for options to pass some data variables to the rendered template – Adams Hales Aug 06 '19 at 10:12
2

Use fs.exists(p, [callback]) to check if the file exists before calling res.render

http://nodejs.org/docs/latest/api/fs.html#fs_fs_exists_path_callback

Node 0.6.x and older

Use path.exists(p, [callback]) to check if the file exists before calling res.render

http://nodejs.org/docs/v0.6.0/api/path.html#path.exists

respectTheCode
  • 42,348
  • 18
  • 73
  • 86
1

Similar to @Augustin Riedinger's answer, the same applies when rendering to variable using renderFile:

var html = jade.renderFile('path/to/file.jade', context, function(err, html) {};
Wtower
  • 18,848
  • 11
  • 103
  • 80
0

You could use fs.open to check if the template exists.

app.use(function (req, res, next) {
    fs.open(__dirname + '/views/' + req.url.substring(1) + '.jade', 'r', function (err) {
      if(err) {
        console.log(err);
        return next();
      }
      res.render(req.url.substring(1), { title: "No Controller", user: req.session.user });
    }
});
generalhenry
  • 17,227
  • 4
  • 48
  • 63
  • res.render has a bunch of logic for figuring out what jade file to use. I was hoping that I wouldn't need to recreate that logic. – respectTheCode Sep 06 '11 at 09:53