Routing Node Applications - MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

Routing Node Applications

To add more pages to our site, we will need more routes. This can be done using a feature built into Express, the Express Router. This is going to be a big chapter since routing is going to be a giant portion of all our applications moving forward. This is how we route basic to advanced websites, and also how we will ultimately build out our RESTful APIs that an Angular frontend application will consume. That’s exciting to look forward that far! One step at a time though. Let’s get to the routing.

Express Router

What exactly is the Express Router? You can consider it a mini express application without all the bells and whistles, just the routing stuff. It doesn’t bring in views or settings, but provides us with the routing APIs like .use(), .get(), .param(), and route(). Let’s take a look at exactly what this means.

There are a few different ways to use the router. We’ve already used one of the methods when we created the home page route in the last chapter by using `app.get(‘/’, …). We’ll look at the other methods by building out more sections of our site and discuss why and when to use them.

Sample Application Features

These are the main features we will add to our current application:

· Basic Routes (We’ve already created the homepage)

· Site Section Routes (Admin section with sub routes)

· Route Middleware to log requests to the console

· Route with Parameters (http://localhost:1337/users/holly)

· Route Middleware for Parameters to validate specific parameters

· Login routes doing a GET and POST on /login

· Validate a parameter passed to a certain route

What is Route Middleware? Middleware is invoked between a user’s request and the final response. We’ll go over this concept when we log data to the console on every request. A user will request the page, we will log it to the console (the middleware), and then we’ll respond with the page they want. More on middleware soon.

Like we’ve done so far, we will keep our routes in the server.js file. We won’t need to make any changes to our package.json file since we already have Express installed.

Basic Routes

We’ve already defined our basic route in the home page. Express let’s us define routes right onto our app object. We can also handle multiple HTTP actions like GET, POST, PUT/PATCH, AND DELETE.

This is the easiest way to define routes, but as our application gets larger, we’ll need more organization for our routes. Just imagine an application that has an administration section and a frontend section, each with multiple routes. Express’s router helps us to organize these when we define them.

For the following routes, we won’t be sending views to the browser, just messages. This will be easier since what we want to focus on is the routing aspects.

express.Router()

The express.Router() acts as a mini application. You can call an instance of it (like we do for Express) and then define routes on that. Let’s look at an example so we know exactly what this means. Add this to your ‘server.js’ file if you’d like to follow along.

Underneath our app.get() route inside of server.js, add the following. We’ll 1. call an instance of the router 2. apply routes to it 3. and then add those routes to our main app

1 // create routes for the admin section

2

3 // get an instance of the router

4 var adminRouter = express.Router();

5

6 // admin main page. the dashboard (http://localhost:1337/admin)

7 adminRouter.get('/', function(req, res) {

8 res.send('I am the dashboard!');

9 });

10

11 // users page (http://localhost:1337/admin/users)

12 adminRouter.get('/users', function(req, res) {

13 res.send('I show all the users!');

14 });

15

16 // posts page (http://localhost:1337/admin/posts)

17 adminRouter.get('/posts', function(req, res) {

18 res.send('I show all the posts!');

19 });

20

21 // apply the routes to our application

22 app.use('/admin', adminRouter);

We will call an instance of the express.Router() and assign it to the adminRouter variable, apply routes to it, and then tell our application to use those routes.

We can now access the admin panel page at http://localhost:1337/admin and the sub-pages at http://localhost:1337/admin/users and http://localhost:1337/admin/posts.

Notice how we can set a default root for using these routes we just defined. If we had changed line 22 to app.use(‘/app’, router), then our routes would be http://localhost:1337/app/ and http://localhost:1337/app/users.

This is very powerful because we can create multiple express.Router()s and then apply them to our application. We could have a Router for our basic routes, authenticated routes, and even API routes.

Using the Router, we are allowed to make our applications more modular and flexible than ever before by creating multiple instances of the Router and applying them accordingly. Now we’ll take a look at how we can use middleware to handle requests.

Route Middleware (router.use())

Route middleware in Express is a way to do something before a request is processed. This could be things like checking if a user is authenticated, logging data for analytics, or anything else we’d like to do before we actually spit out information to our user.

Here is some middleware to log a message to our console every time a request is made. This will be a demonstration of how to create middleware using the Express Router. We’ll just add the middleware to the adminRouter we created in the last example. Make sure that this is placed afteryour adminRouter declaration and before the users and posts routes we defined. You’ll also notice the ‘next’ argument here. This is the only way that Express will know that the function is complete and it can proceed with the next piece of middleware or continue on to the routing.

1 // route middleware that will happen on every request

2 adminRouter.use(function(req, res, next) {

3

4 // log each request to the console

5 console.log(req.method, req.url);

6

7 // continue doing what we were doing and go to the route

8 next();

9 });

adminRouter.use() is used to define middleware. This will now be applied to all of the requests that come into our application for this instance of Router. Let’s go into our browser and go to http://localhost:1337/admin and we’ll see the request in our console.

Express Router Console Request

Express Router Console Request

The order you place your middleware and routes is very important Everything will happen in the order that they appear. This means that if you place your middleware after a route, then the route will happen before the middleware and the request will end there. Your middleware will not run at that point.

Keep in mind that you can use route middleware for many things. You can use it to check that a user is logged in during the session before letting them continue.

Structuring Routes

By using the Router(), we are able to section off parts of our site. This means you can create a basicRouter for routes like the frontend of the site. You could also create an adminRouter for administration routes that would be protected by some sort of authentication.

Routing our application this way let’s us compartmentalize each piece. This provides us the flexibility that we need for complex applications or APIs. We can also keep our applications clean and organized since we can move each router definition into its own file and then just pull in those files when we call app.use() like so:

1 app.use('/', basicRoutes);

2 app.use('/admin', adminRoutes);

3 app.use('/api', apiRoutes);

Routes with Parameters (/hello/:name)

To see how we can add route parameters to our application, let’s say we wanted to have a route called /admin/users/:name where we could pass in a person’s name into the URL and the application would spit out Hello name! (we could also use this in a real application in order to pull the information for that user. Let’s see what that sort of route would look like.

1 // route with parameters (http://localhost:1337/admin/users/:name)

2 adminRouter.get('/users/:name', function(req, res) {

3 res.send('hello ' + req.params.name + '!');

4 });

Now we can visit http://localhost:1337/admin/users/holly and see our browser spit out hello holly! req.params stores all the data that comes from the original user’s request. Easy cheesy.

Express Router Parameters

Express Router Parameters

In the future, we could use this to grab all the user data that matches the name holly. We could then build an administration panel to manage our users.

Now let’s say we wanted to validate this name somehow. Maybe we’d want to make sure it wasn’t a naughty word. We would do that validation inside of route middleware. We’ll use a special middleware for this.

Route Middleware for Parameters (.param())

We will use Express’s .param() middleware. This creates middleware that will run for a certain route parameter. In our case, we are using :name in our hello route. Here’s the param middleware. Again, make sure the middleware is placed before the request.

1 // route middleware to validate :name

2 adminRouter.param('name', function(req, res, next, name) {

3 // do validation on name here

4 // blah blah validation

5 // log something so we know its working

6 console.log('doing name validations on ' + name);

7

8 // once validation is done save the new item in the req

9 req.name = name;

10 // go to the next thing

11 next();

12 });

13

14 // route with parameters (http://localhost:1337/admin/hello/:name)

15 adminRouter.get('/hello/:name', function(req, res) {

16 res.send('hello ' + req.name + '!');

17 });

Now when we hit the /hello/:name route, our route middleware will kick in and be used. We can run validations and then we’ll pass the new variable to our .get route by storing it in req (request). We then access it by changing req.params.name to req.name since we took req.params.nameand stored it into req in the middleware.

When we visit our browser at http://localhost:1337/admin/hello/sally we’ll see our request logged to the console.

Express Router Parameter Middleware

Express Router Parameter Middleware

Route middleware for parameters can be used to validate data coming to your application. If you have created a RESTful API also, you can validate a token and make sure the user is able to access your information. All of the work we’ve done with Node so far will lead to building a RESTful API that will become the server-side application that we talked about Chapter 3 when we spoke about the client-server model.

The last Express router feature that we’ll look at is how to use app.route() to define multiple routes at once.

Login Routes (app.route())

We can define our routes right on our app. This is similar to using app.get, but we will use app.route. app.route is basically a shortcut to call the Express Router. Instead of calling express.Router(), we can call app.route and start applying our routes there.

Using app.route() lets us define multiple actions on a single login route. We’ll need a GET route to show the login form and a POST route to process the login form.

1 app.route('/login')

2

3 // show the form (GET http://localhost:1337/login)

4 .get(function(req, res) {

5 res.send('this is the login form');

6 })

7

8 // process the form (POST http://localhost:1337/login)

9 .post(function(req, res) {

10 console.log('processing');

11 res.send('processing the login form!');

12 });

Now we have defined our two different actions on our /login route. Simple and very clean. These are applied directly to our main app object in the ‘server.js’ file, but we can also define them in the adminRouter object we had earlier.

This is a good method for setting up routes since it is clean and makes it easy to see which routes are applied where. We’ll be building a RESTful API soon and one of the main things we should do is use different HTTP verbs to signify actions on our application. GET /login will provide the login form while POST /login will process the login.

Recap

With the Express Router, we are given much flexibility when defining routes. To recap, we can:

· Use express.Router() multiple times to define groups of routes

· Apply the express.Router() to a section of our site using app.use()

· Use route middleware to process requests

· Use route middleware to validate parameters using .param()

· Use app.route() as a shortcut to the Router to define multiple requests on a route

Now that we’ve got a solid foundation of Node and Express, let’s move forward and talk a little more about MongoDB. Then we’ll get to the main part of our server-side applications: Building APIs!