Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Express Basics Getting Started with Express Adding Multiple Routes to the App

Express.js Routing flow... is this correct???

Hi there. I am trying to understand the routing flow in Express from the time a user enters a URL in their browser to when the response is returned. But I don't quite understand the paths that are used in-between. Is the following correct?

  1. User enters a URL in their browser, say www.website.com/articles. By default the browser makes a GET request.

  2. The request hits the entry file (let's call it app.js) and searches for a match for /articles. It finds it here:

app.use('/articles', articlesRouter);
  1. Because it finds a match for the endpoint the user specified, Express follows the path stored in the articlesRouter variable:
var articlesRouter = require('./routes/articles');
  1. Express looks in the routes/articles.js file for (a) http verb that matches the request (in this case, GET) and (b) an endpoint that matches the one the user entered in the URL bar:
router.get('/articles', (req, res, next) => {
             res.render('articles.ejs');
  });
  1. When Express sees res.render('articles'), it looks in the views folder by default for a view file that matches the one specified - in this case articles.ejs

My question: Did I get any part of this wrong? I'm really unclear about the process from start to finish, especially the paths. I am not even sure it the paths refer to the URL the user enters in the browser or the files that are available to be served in the app.

Any help from veteran node-ers apprieciated!!!

1 Answer

Hey Francis, I think you have the process pretty well down pat. When a browser makes a request, first the server port will receive that request on a low level and do it's thing with it, pass it on up from the physical layer to the software layer where the entry point receives it. The request is then processed by any middleware in the order in which the middleware is "used", and then when it reaches a matching route it will be processed by the function or controller method assigned to handle requests for that route. I think you understand this better than you realize.

In terms of paths, they are really just strings that we use to map URIs (Uniform Resource Locator - e.g "/article", "/article?id=01234" etc) to function calls that perform any necessary data processing or database interaction and then serve a response to the client. The paths you pass to the router object in Express do not refer to specific files.

Say you have a personal blog site, and your blog posts are stored in a database. You will probably have a route that looks like this:

// this is your controller. It is a closure. If you don't understand closures take the Treehouse closure workshop
const renderArticle = require('/path/to/controller')();

// ":id" is a placeholder variable for any url parameter passed to it like "/articles/5"
router.get('/articles/:id', renderArticle);

You will then have a controller that handles getting the required data and rendering the view (a controller is an object or module that handles the task of getting data from a database and passing that data to the view, or performing any other logic associated with sending your user the correct view. If you haven't already, read about the Model View Controller architectural design pattern) that looks like this:

// this module is your renderArticle controller. It is a closure, meaning it is a function that returns a function

// in reality this would be an async function but I left that out for simplicity

const dataBaseModel = require('/path/to/dataBaseModel');

module.exports = () => {
  return (req, res) => {
    // get the unique id for the article
    const articleID = req.params.id;

    // get the article from the database using it's unique id
    const article = dataBaseModel.getArticle(articleID);

    // add the article to the args variable to be injected into the view
    const args = { article };

    // render your article.pug file passing the args variable to it 
    return res.render('article', args);
  } 
}

So what happens is that when the user visits yourblog.com/articles/5 it matches with the route that you've decided to label "articles", and then that route executes the callback function passed to it, and ideally, the callback function you pass to it correctly does the work of requiring and calling any database model methods and then passing the data returned from those database calls back to the view. Your pug file could be called "supercalifragilisticexpialidocious.pug" for all Express cares. It isn't the name of the file that matters. It just matters that the url parameter that the browser uses in the request actually matches to a route that you've written.

I hope this makes sense. If you think you need any more clarification let me know in the comments and I'll try to answer it clearly.

One point of clarification: I made it sound like it's the job of the controller to get data from a databse. This isn't true. Models are modules or objects whose responsibility it is to interact with a database. In the MVC pattern, controllers require or import models and call them, but the model handles all database interactivity. The controller simply calls it and then takes the data returned from a model and passes it to the view.