Lesson 9. Routing in Express.js

In lesson 8, I introduced Express.js as a framework for Node.js web applications. The rest of this unit is dedicated to exploring Express.js functionality and using its convenient methods. This lesson covers routing and how a few more Express.js methods allow you to send meaningful data to the user before building a view. You also walk through the process of collecting a request’s query string. The lesson ends by touching on the MVC design pattern.

This lesson covers

  • Setting up routes for your application
  • Responding with data from another module
  • Collecting request URL parameters
  • Moving route callbacks to controllers
Consider this

You want to build a home-page view for your recipe application that people can visit to see an estimated date of completion for your application. With your new, clean Express.js setup, you’d like to keep the date variable in a separate file that you can easily change without modifying your main.js file.

After setting up your routes, you’ll be able to store some data in a separate module and respond dynamically with that data. With the separate module, you’ll be able to modify that file’s contents without needing to edit your main application file. This structure helps prevent you from making mistakes in your code while constantly changing values.

9.1. Building routes with Express.js

In lesson 8, you constructed your first Express.js application, consisting of a route handling GET requests to your home-page URL. Another way to describe this route is as an application endpoint that takes an HTTP method and path (URL). Routes in Express.js should look familiar to you because you built the same routing structure at the end of unit 1. 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 the following listing. This example uses the post method provided by Express.js.

Listing 9.1. Express.js POST route in main.js
app.post("/contact", (req, res) => {                            1
  res.send("Contact information submitted successfully.");
});

  • 1 Handle requests with the Express.js post method.

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, which I talk about at the end of this lesson.) Route parameters have a colon (:) before the parameter and can exist anywhere in the path. Listing 9.2 shows an example of a route with parameters. The route in this listing expects a request made to /items/ plus some vegetable name or number. A request to "/items/lettuce", for example, would trigger the route and its callback function. The response sends the item from the URL back to the user through the params property of the request object.

Listing 9.2. Using route parameters to indicate vegetable type in main.js
app.get("/items/:vegetable", (req, res) => {          1
 res.send(req.params.vegetable);
});

  • 1 Respond with path parameters.

Initialize 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 shown in listing 9.2. At this point, your main.js should look like the code in the next listing.

Listing 9.3. Complete Express.js example in main.js
const port = 3000,
  express = require("express"),
  app = express();

app.get("/items/:vegetable", (req, res) => {        1
  let veg = req.params.vegetable;
  res.send(`This is the page for ${veg}`);
});

app.listen(port, () => {
  console.log(`Server running on port: ${port}`);
});

  • 1 Add a route to get URL parameters.

Route parameters are handy for specifying data objects in your application. When you start saving user accounts and course listings in a database, for example, you might access a user’s profile or specific course with the /users/:id and/course/:type paths, respectively. This structure is necessary for developing a representational state transfer (REST) architecture, as you learn in unit 4.

One last note on Express.js routes: I talked about how 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 task by adding a log message to every route or by creating the middleware function in listing 9.4. This listing defines a middleware function with an additional next argument, logs the request’s path to your terminal console, and then calls the next function to continue the chain in the request-response cycle.

next is provided as a way of calling the next function in your request-response execution flow. From the time a request enters the server, it accesses a series of middleware functions. Depending on where you add your own custom middleware function, you can use next to let Express.js know that your function is complete and that you want to continue to whatever function is next in the chain.

As with HTTP methods, you can create a route with app.use that runs on every request. The difference 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 its URL path matches with any other routes in your application. When 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, the request is processed first by your middleware function and then by the app.get("/items/:vegetable") route you created previously.

Listing 9.4. Express.js middleware function for logging request path in main.js
app.use((req, res, next) => {                    1
  console.log(`request made to: ${req.url}`);    2
  next();                                        3
});

  • 1 Define a middleware function.
  • 2 Log the request’s path to console.
  • 3 Call the next function.
Warning

Calling next at the end of your function is necessary to alert Express.js that your code has completed. Not doing so leaves your request hanging. Middleware runs sequentially, so by not calling next, you’re blocking your code from continuing until completion.

You can also specify a path for which you’d like your middleware function to run. app.use("/items", <callback>), for example, will run your custom callback function for every request made to a path starting with items. Figure 9.1 shows how middleware functions can interact with a request on the server.

Figure 9.1. The role of middleware functions

In the next section, I talk about handling data in your routes and responding with that data.

Quick check 9.1

Q1:

What does the Express.js use method do?

QC 9.1 answer

1:

The use method allows you to define the middleware functions you want to use with Express.js.

 

9.2. Analyzing request data

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

You have two main ways to get data from the user:

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

In the first capstone project, you successfully built a form that submits data to a POST route (a route that listens for posted data to a specific URL). But http incoming data is represented as a Buffer stream, which is not 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.16.0), you add express.json and express.urlencoded to your app instance to analyze incoming request bodies. Notice the use of req.body to log posted data to the console in listing 9.5. Add that code to your project’s main.js. With Express.js’ app.use, specify that you want to parse incoming requests that are URL-encoded (usually, form post and utf-8 content) and in JSON format. Then create a new route for posted data. This process is as simple as using the post method and specifying a URL. Finally, print the contents of a posted form with the request object and its body attribute.

Listing 9.5. Capturing posted data from the request body in main.js
app.use(
  express.urlencoded({
    extended: false
  })
);                                1
app.use(express.json());

app.post("/", (req, res) => {     2
  console.log(req.body);          3
  console.log(req.query);
  res.send("POST Successful!");
});

  • 1 Tell your Express.js application to parse URL-encoded data.
  • 2 Create a new post route for the home page.
  • 3 Log the request’s body.

Test this code by submitting a POST request to http://localhost:3000, using the following curl command: curl --data "first_name=Jon&last_name=Wexler" http://localhost:3000.

You should see the body logged to your server’s console window like so: { first_name: "Jon", last_name:Wexler" }.

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

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

Examine the following sample URL: http://localhost:3000?cart=3&pagesVisited=4&utmcode=837623. This URL might be passing information about the number of items in a 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 in main.js. Now try visiting the same URL. You should see { cart: "3", pagesVisited: "4", utmcode: "837623" } logged to your server’s console window.

In the next section, I talk about MVC architecture and how Express.js routes fit into that structure.

Quick check 9.2

Q1:

What additional middleware functions are needed to parse incoming data in a request body with Express.js?

QC 9.2 answer

1:

The express.json and express.urlencoded for parsing incoming data to the server. Other packages, such as body-parser, act as middleware and perform similar tasks.

 

9.3. Using MVC

This lesson is about processing 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 code base, you’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 used views in past applications to display HTML in the response. See the breakdown and definitions in table 9.1.

Table 9.1. Model-view-controller parts
Views Rendered displays of data from your application. In unit 3, you learn about models and even create your own.
Models Classes that represent object-oriented data in your application and database. In your recipe application, you might create a model to represent a customer order. Within this model, you define what data an order should contain and the types of functions you can run on that data.
Controllers The glue between views and models. Controllers perform most of the logic when a request is received to determine how request body data should be processed and how to involve the models and views. This process should sound familiar, because in an Express.js application, your route callback functions act as controllers.

To follow the MVC design pattern, move your callback functions to separate modules that reflect the purposes of those functions. Callback functions related to user account creation, deletion, or changes, for example, go in a file called usersController.js within the controllers folder. Functions for routes that render the home page or other informational pages can go in homeController.js by convention. Figure 9.2 shows the file structure that your application will follow.

Figure 9.2. Express.js MVC file structure

Figure 9.3 shows Express.js as a layer over your application that handles requests but also feeds your application’s controllers. The callbacks decide whether a view should be rendered or some data should be sent back to the client.

Figure 9.3. 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:

  1. Create a controllers folder within your project folder.
  2. Create a homeController.js file within controllers.
  3. Require your home controller file into your application by adding the following to the top of main.js:
    const homeController = require("./controllers/homeController");
  4. Move your route callback functions to the home controller, and add them to that module’s exports object. Your route to respond with a vegetable parameter, for example, can move to your home controller to look like listing 9.6. In homeController.js, you assign exports.sendReqParam to the callback function. sendReqParam is a variable name, so you can choose your own name that describes the function.
    Listing 9.6. Moving a callback to homeController.js
    exports.sendReqParam = (req, res) => {              1
      let veg = req.params.vegetable;
      res.send(`This is the page for ${veg}`);
    };

    • 1 Create a function to handle route-specific requests.
  5. Back in main.js, change the route to look like the next listing. When a request is made to this path, the function assigned to sendReqParam in the home controller is run.
    Listing 9.7. Replacing a callback with a controller function in main.js
    app.get("/items/:vegetable", homeController.sendReqParam);     1

    • 1 Handle GET requests to “/items/:vegetable”.
  6. Apply this structure to the rest of your routes, and continue to use the controller modules to store the routes’ callback function. You can move your request-logging middleware to a function in the home controller referenced as logRequestPaths, for example.
  7. Restart your Node.js application, and see that the routes still work. With this setup, your Express.js application is taking on a new form with MVC in mind.

In the next lesson, I discuss how to serve views and assets with Express.js.

Installing and using express-generator

As you continue to evolve your Express.js application, you adhere to a specific file structure. You have many ways to construct your application, though, depending on its intended use. To jump-start your application in the Express.js framework, you can use a package called express-generator.

express-generator provides some boilerplate code for an application. This tool offers scaffolding (prebuilt folders, modules, and configurations) that might have taken you a few hours to build from scratch. To install this package, use the global flag with the npm install command. Enter the following command in terminal: npm install express-generator -g. For UNIX machines, you may need to prepend this command with sudo or run it as an administrator.

When this package is installed, you can create a new project by entering express and the project name in a new terminal window. If your project is called Generation Generator, for example, enter express generation_generator in terminal. The express keyword in this context uses express-generator in terminal to construct the application with some views and routes.

Although this tool is great for constructing applications quickly, I don’t recommend using it while running the exercises in this book. You should use a slightly different application structure from the one provided by express-generator. For more information about this package, visit https://expressjs.com/en/starter/generator.html.

Quick check 9.3

Q1:

What is the role of controllers in MVC?

QC 9.3 answer

1:

Controllers are responsible for processing data by communicating with models, performing code logic, and calling for a view to be rendered in a server’s response.

 

Summary

In this lesson, you learned how to build routes and middleware functions with Express.js. Then you used middleware functions to work with Express.js in analyzing request body contents. At the end of the lesson, you learned about MVC and saw how routes can be rewritten to use controllers in your application. In lesson 10, you jump into views and a rich feature known as layouts. With these tools, you can build your views faster.

Try this

You have 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 userSignUpProcessor.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.61.142