From Get Programming with Node.js by Jonathan Wexler

This article covers routing and how a few more Express.js methods allow you to send meaningful data to the user before building a view. We’ll also walk through collecting a request’s query string. The article ends touching on the MVC design pattern.


Save 37% off Get Programming with Node.js. Just enter fccwexler into the discount code box at checkout at manning.com.


What is Routing?

Routing is a way for your application to determine how to respond to a requesting client. Some routes are designed simply by matching the URL in the request object. That is how you’re going to build your routes in this lesson.

Each request object has a url property. You can view which URL was requested by the client with req.url. Test this out and two other properties by logging them to your console. Add the following code in listing 1 to the server.on('request') code block.

Listing 1. Logging request data in main.js

  
 console.log(req.method);
 console.log(req.url);
 console.log(req.headers);
  

Building routes with Express.js

In Express.js, a route definition starts with your app object, followed by a lowercase HTTP method and its arguments: the route path and callback function.

A route handling POST requests to the /contact path should look like listing 2.

Listing 2. Express.js POST route

  
 app.post('/contact', (req,res) => {  
 res.send("Contact information
 submitted successfully.");
 });
  

More HTTP methods exist than GET and POST and you can learn more about them at https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol.

You can use these HTTP methods on the app object because app is an instance of the main Express.js framework class. By installing this package, you inherited routing methods without needing to write any other code.

Express.js lets you write routes with parameters in the path. These parameters are a way of sending data through the request. Another way is with query strings. Route parameters have a colon (:) before the parameter and can exist anywhere in the path. See the following example of a route with parameters in listing 3.

Listing 3. Using route parameters to indicate CSA vegetable type

  
 app.get('/items/:vegetable', (req, res) => { 
    res.send(req.params.vegetable);           
 });
  

This route expects a request made to /items/ + some vegetable name or number. For example, a request to ‘/items/lettuce’ triggers the route and its callback function.

This response sends the item from the URL back to the user through the params property on the request object.

Try initializing a new project called express_routes, install Express.js, and add the code to require and instantiate the Express.js module. Then create a route with parameters and respond with that parameter as in listing 3.

Route parameters are handy for specifying specific data objects in your application.

For example, once you start saving user accounts and course listings in a database, you might access a user’s profile or specific course with /users/:id and /course/:type, respectively.

One last note on Express.js routes. Express.js is a type of middleware because it adds a layer between a request being received and that request being processed. This feature is great, but you may want to add your own custom middleware. You may want to log the path of every request made to your application for your own records, for example. You can accomplish this by adding a log message to every route, or by creating the middleware function in listing 4.

Listing 4. Express.js middleware function for logging request path

  
 app.use((req, res, next) => {                  
    console.log(`request made to: ${req.url}`); 
   next();                                      
 });
  

Define a middleware function with an additional next argument

Log the request’s path to your terminal console

❸  Call the next function to continue the chain in the request-response cycle.

 

What is Middleware?

According to Express.js documentation Middleware functions are functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle. The next middleware function is commonly denoted by a variable named next.

As with HTTP methods, you can create a route with app.use() which runs on every request. The difference here is that you’re adding an additional argument in the callback, the next function. This middleware function allows you to run custom code on the request before it matches with any other routes in your application. Once your custom code completes, next() points the request to the next route that matches its path. Try adding this middleware function to your express_routes application. If a request is made to /items/lettuce, it’s first be processed by your middleware function and then by the app.get('/items/:vegetable') route you created previously.

Calling next() at the end of your function is necessary to alert Express.js that your code is completed. Not doing this leaves your request hanging. You can also specify a path for which you’d like your middleware function to run. For example, app.use('/items', callback) runs for every request made to a path starting with items.

Next, we’ll talk about handling data in your routes and responding with that data.

 

Quick Check Exercise

QC 1 What does the Express.js use() method do?

Analyzing Request data

Preparing fancy and dynamic responses are important in your application, but eventually you’ll need to demonstrate the application’s ability to capture data from the user’s request.

Two main ways which we can get data from the user are:

  • through the request body in a POST request
  • through the request’s query string in the URL

Http incoming data is represented as a Buffer stream, which isn’t human readable and adds an extra step to making that data accessible for processing.

Express.js makes retrieving the request body easy with the body attribute. To assist in reading the body contents (as of Express.js version 4) we’ll need to install an additional package. Go to your project folder in your command line and enter the command in listing 5.

Listing 5. Installing the body-parser package

  
 npm install body-parser –save
  

body-parser is a module used for analyzing incoming request bodies. This module used to come prepackaged with Express.js. To make use of it we’ll need to require the module into your application. Notice the use of req.body to log posted data to the console in listing 6. Add that code to your project’s main.js.

Listing 6. Capturing posted data from the request body

  
 const bodyParser = require('body-parser');             
  app.use(bodyParser.urlencoded({ extended: false }));  
  app.use(bodyParser.json());
 app.post('/', (req, res) =>{                           
    console.log(req.body);                              
 });
  

❶  We require the body-parser module and assign it to a constant.

❷  With Express.js’ app.use() we specify that we’ll want to parse incoming requests which are URL-encoded (usually form post and utf-8 content) and JSON formats.

❸  creating a new route for posted data is as simple as using the post() method and specifying a URL.

❹  we can print the contents of a posted form with the request object and its body attribute

Test this out by submitting a POST request to http://localhost:3000 using the curl command in listing 7.

Listing 7. Capturing posted data from the request body

  
 curl --data "first_name=Jon&last_name=Wexler" http://localhost:3000
  

You should see the body logged to your server’s console window as shown in listing 8.

Listing 8. req.body logged to console

  
 { first_name: 'Jon', last_name: 'Wexler' }
  

Now when you demo the backend code to your customer you can show them, through a mocked form submission, how data is collected on the server.

Another way we can collect data is through the URL parameters. Without the need of an additional package, Express.js lets us collect values stored at the end of our URL’s path, following a ?. These are called query strings, and they’re often used for tracking user activity on a site and storing temporary information about the user’s visited pages.

For example, let’s examine a sample URL in listing 9.

Listing 9. req.body logged to console

  
 http://localhost:3000?cart=3&pagesVisited=4&utmcode=837623 
  

❶  This URL might be passing information about the number of items in the user’s shopping cart, the number of pages they’ve visited, and a marketing code to let the site owners know how this user found your app in the first place.

To see these query strings on the server, add console.log(req.query); to your middleware function. Now try visiting the URL in listing 8. You should see { cart: '3', pagesVisited: '4', utmcode: '837623' } logged to your server’s console window.

Next, we’ll talk about the MVC architecture and how Express.js routes fit in that structure.

 

Quick Check Exercise

QC 2 What additional package is needed to parse incoming data in a request body with Express.js?

Express.js and MVC

This article has been about processing of request data within your routes. Express.js opens the door to custom modules and code to read, edit, and respond with data within the request-response cycle. To organize this growing codebase, we’re going to follow an application architecture known as MVC.

MVC architecture focuses on three main parts of your application’s functionality: models, views, and controllers. You’ve already used views in past applications to display HTML in the response. Views are that – rendered displays of data from your application. Models are classes to represent object-oriented data in your application and database. For example, in your CSA application you might create a model to represent a customer order. Within this model you’ll define what data an order should contain and the types of functions you can run on that data.

Controllers are the glue between views and models. Controllers perform most of the logic once a request is received to determine how request body data should be processed and how to involve the models and views. This should sound familiar because in an Express.js application your route callback functions act as the controllers.

To follow the MVC design pattern, you’ll move your callback functions to separate modules reflecting the purpose of those functions. For example, callback functions related to user account creation, deletion, or change go in a file called userController.js within the controllers folder. Functions for routes that render the homepage or other informational pages can go in the homeController.js, by convention. See figure 1 for the file structure your application follows.


Figure 1. Express.js MVC file structure


Figure 2 shows how Express.js is a layer over your application to handle requests, but also feeds your application’s controllers. The callbacks decide if a view should be rendered or some data sent back to the client.


Figure 2. Express.js can follow the MVC structure with routes feeding controllers


To restructure your express_routes application to adhere to this structure, follow these steps:

  • Start by creating a controllers folder within your project folder.
  • Create a homeController.js file within controllers
  • Require your home controller file into your application by adding the following to the top of main.js.let homeController = require(‘./controllers/homeController’);
  • Move your route callback functions to the home controller and add them to that module’s exports object. For example, your route to respond with a vegetable parameter can move to your home controller to look like listing 10.

    Listing 10. Moving a callback to the home controller

      
     exports.send_req_param = (req, res) => { 
        let veg = req.params.vegetable;
       res.send(`This is the page for ${veg}`);
     }
      
    

    In homeController.js we assign exports.send_req_param to the callback function. send_req_param is a variable name, you can choose your own name which is descriptive of the function.

  • Back in main.js we’ll change the route to look like listing 11.

    Listing 11. Replacing a callback with a reference to a controller function

      
     app.get('/items/:vegetable', homeController.send_req_param); 
      
    

    When a request is made to this path the function assigned to send_req_param in the home controller’s run.

Apply this structure to the rest of your routes and continue to use the controller modules to store the routes’ callback function. With this setup, your Express.js is taking on a new form with MVC in mind.

 

Quick Check Exercise

QC 3 What’s the role of controllers in MVC?

Summary

In this article you learned how to build routes and middleware functions with Express.js. Then you installed the body-parser package to work with Express.js in analyzing request body contents. At the end of the article you learned about MVC and how routes can be rewritten to make use of controllers in your application.

 

Try this

You’ve the directory structure set up for an MVC Express.js application. Try creating a POST route for the /sign_up path using Express.js methods and controller functions for the route’s callback.

The    function’s            name     in          the        controller            can        read       something           like user_sign_up_processor.

Answers to Quick Check Exercises

QC 1 The use() method allows you to define middleware functions you want to use with Express.js.
QC 2 The body-parser package offers a library of code for parsing incoming data to the server. Other packages act as middleware and perform similar tasks.
QC 3 Controllers are responsible for processing data by communicating with models, performing code logic, and call for a view to be rendered in a server’s response.

Hopefully, you even more interested in learning Node.js than you were at the beginning of this article. If you want to learn more about the book, check it out on liveBook here and see this slide deck.