Express Tutorial Part 2: Creating a skeleton website - Learn web development

Express Tutorial Part 2: Creating a skeleton website
====================================================

* Previous
* Overview: Express Nodejs
* Next

This second article in our Express Tutorial shows how you can create a "skeleton" website project which you can then go on to populate with site-specific routes, templates/views, and database calls.

|  |  |
| --- | --- |
| Prerequisites: | Set up a Node development environment.
 Review the Express Tutorial.
  |
| Objective: | To be able to start your own new website projects using the *Express Application Generator*. |

Overview
--------

This article shows how you can create a "skeleton" website using the Express Application Generator tool, which you can then populate with site-specific routes, views/templates, and database calls. In this case, we'll use the tool to create the framework for our Local Library website, to which we'll later add all the other code needed by the site. The process is extremely simple, requiring only that you invoke the generator on the command line with a new project name, optionally also specifying the site's template engine and CSS generator.

The following sections show you how to call the application generator, and provides a little explanation about the different view/CSS options. We'll also explain how the skeleton website is structured. At the end, we'll show how you can run the website to verify that it works.

**Note:**

* The *Express Application Generator* is not the only generator for Express applications, and the generated project is not the only viable way to structure your files and directories. The generated site does however have a modular structure that is easy to extend and understand. For information about a *minimal* Express application, see Hello world example (Express docs).
* The *Express Application Generator* declares most variables using `var`.
 We have changed most of these to `const` (and a few to `let`) in the tutorial, because we want to demonstrate modern JavaScript practice.
* This tutorial uses the version of *Express* and other dependencies that are defined in the **package.json** created by the *Express Application Generator*.
 These are not (necessarily) the latest version, and you may want to update them when deploying a real application to production.

Using the application generator
-------------------------------

You should already have installed the generator as part of setting up a Node development environment. As a quick reminder, you install the generator tool site-wide using the npm package manager, as shown:

```bash
npm install express-generator -g
```

The generator has a number of options, which you can view on the command line using the `--help` (or `-h`) command:

```bash
> express --help

    Usage: express [options] [dir]

  Options:

        --version        output the version number
    -e, --ejs            add ejs engine support
        --pug            add pug engine support
        --hbs            add handlebars engine support
    -H, --hogan          add hogan.js engine support
    -v, --view <engine>  add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
        --no-view        use static html instead of view engine
    -c, --css <engine>   add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain CSS)
        --git            add .gitignore
    -f, --force          force on non-empty directory
    -h, --help           output usage information
```

You can specify express to create a project inside the *current* directory using the *Jade* view engine and plain CSS (if you specify a directory name then the project will be created in a sub-folder with that name).

```bash
express
```

You can also choose a view (template) engine using `--view` and/or a CSS generation engine using `--css`.

**Note:** The other options for choosing template engines (e.g. `--hogan`, `--ejs`, `--hbs` etc.) are deprecated. Use `--view` (or `-v`).

### What view engine should I use?

The *Express Application Generator* allows you to configure a number of popular view/templating engines, including EJS, Hbs, Pug (Jade), Twig, and Vash, although it chooses Jade by default if you don't specify a view option. Express itself can also support a large number of other templating languages out of the box.

**Note:** If you want to use a template engine that isn't supported by the generator then see Using template engines with Express (Express docs) and the documentation for your target view engine.

Generally speaking, you should select a templating engine that delivers all the functionality you need and allows you to be productive sooner — or in other words, in the same way that you choose any other component! Some of the things to consider when comparing template engines:

* Time to productivity — If your team already has experience with a templating language then it is likely they will be productive faster using that language. If not, then you should consider the relative learning curve for candidate templating engines.
* Popularity and activity — Review the popularity of the engine and whether it has an active community. It is important to be able to get support when problems arise throughout the lifetime of the website.
* Style — Some template engines use specific markup to indicate inserted content within "ordinary" HTML, while others construct the HTML using a different syntax (for example, using indentation and block names).
* Performance/rendering time.
* Features — you should consider whether the engines you look at have the following features available:
    + Layout inheritance: Allows you to define a base template and then "inherit" just the parts of it that you want to be different for a particular page. This is typically a better approach than building templates by including a number of required components or building a template from scratch each time.
    + "Include" support: Allows you to build up templates by including other templates.
    + Concise variable and loop control syntax.
    + Ability to filter variable values at template level, such as making variables upper-case, or formatting a date value.
    + Ability to generate output formats other than HTML, such as JSON or XML.
    + Support for asynchronous operations and streaming.
    + Client-side features. If a templating engine can be used on the client this allows the possibility of having all or most of the rendering done client-side.

**Note:** There are many resources on the Internet to help you compare the different options!

For this project, we'll use the Pug templating engine (this is the recently-renamed Jade engine), as this is one of the most popular Express/JavaScript templating languages and is supported out of the box by the generator.

### What CSS stylesheet engine should I use?

The *Express Application Generator* allows you to create a project that is configured to use the most common CSS stylesheet engines: LESS, SASS, Compass, Stylus.

**Note:** CSS has some limitations that make certain tasks difficult. CSS stylesheet engines allow you to use more powerful syntax for defining your CSS and then compile the definition into plain-old CSS for browsers to use.

As with templating engines, you should use the stylesheet engine that will allow your team to be most productive. For this project, we'll use vanilla CSS (the default) as our CSS requirements are not sufficiently complicated to justify using anything else.

### What database should I use?

The generated code doesn't use/include any databases. *Express* apps can use any database mechanism supported by *Node* (*Express* itself doesn't define any specific additional behavior/requirements for database management).

We'll discuss how to integrate with a database in a later article.

Creating the project
--------------------

For the sample *Local Library* app we're going to build, we'll create a project named *express-locallibrary-tutorial* using the *Pug* template library and no CSS engine.

First, navigate to where you want to create the project and then run the *Express Application Generator* in the command prompt as shown:

```bash
express express-locallibrary-tutorial --view=pug
```

The generator will create (and list) the project's files.
```

   create : express-locallibrary-tutorial\
   create : express-locallibrary-tutorial\public\
   create : express-locallibrary-tutorial\public\javascripts\
   create : express-locallibrary-tutorial\public\images\
   create : express-locallibrary-tutorial\public\stylesheets\
   create : express-locallibrary-tutorial\public\stylesheets\style.css
   create : express-locallibrary-tutorial\routes\
   create : express-locallibrary-tutorial\routes\index.js
   create : express-locallibrary-tutorial\routes\users.js
   create : express-locallibrary-tutorial\views\
   create : express-locallibrary-tutorial\views\error.pug
   create : express-locallibrary-tutorial\views\index.pug
   create : express-locallibrary-tutorial\views\layout.pug
   create : express-locallibrary-tutorial\app.js
   create : express-locallibrary-tutorial\package.json
   create : express-locallibrary-tutorial\bin\
   create : express-locallibrary-tutorial\bin\www

   change directory:
     > cd express-locallibrary-tutorial

   install dependencies:
     > npm install

   run the app (Bash (Linux or macOS))
     > DEBUG=express-locallibrary-tutorial:* npm start

   run the app (PowerShell (Windows))
     > $ENV:DEBUG = "express-locallibrary-tutorial:*"; npm start

   run the app (Command Prompt (Windows)):
     > SET DEBUG=express-locallibrary-tutorial:* & npm start
```

At the end of the output, the generator provides instructions on how to install the dependencies (as listed in the **package.json** file) and how to run the application on different operating systems.

**Note:** The generator-created files define all variables as `var`.
 Open all of the generated files and change the `var` declarations to `const` before you continue (the remainder of the tutorial assumes that you have done so).

Running the skeleton website
----------------------------

At this point, we have a complete skeleton project. The website doesn't actually *do* very much yet, but it's worth running it to show that it works.

1. First, install the dependencies (the `install` command will fetch all the dependency packages listed in the project's **package.json** file).

```bash
cd express-locallibrary-tutorial
npm install
```

2. Then run the application.
    * On the Windows CMD prompt, use this command:
     batch
    ```batch
    SET DEBUG=express-locallibrary-tutorial:\* & npm start

    ```
    * On Windows Powershell, use this command:
     powershell
    ```powershell
    ENV:DEBUG = "express-locallibrary-tutorial:\*"; npm start

    ```

    **Note:** Powershell commands are not covered in this tutorial (The provided "Windows" commands assume you're using the Windows CMD prompt.)
    * On macOS or Linux, use this command:
     bash
    ```bash
    DEBUG=express-locallibrary-tutorial:* npm start

    ```
3. Then load `http://localhost:3000/` in your browser to access the app.

You should see a browser page that looks like this:

![Browser for default Express app generator website](/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website/expressgeneratorskeletonwebsite.png)

Congratulations! You now have a working Express application that can be accessed via port 3000.

**Note:** You could also start the app just using the `npm start` command. Specifying the DEBUG variable as shown enables console logging/debugging. For example, when you visit the above page you'll see debug output like this:

```bash
SET DEBUG=express-locallibrary-tutorial:* & npm start
```

```
> express-locallibrary-tutorial@0.0.0 start D:\github\mdn\test\exprgen\express-locallibrary-tutorial
> node ./bin/www

  express-locallibrary-tutorial:server Listening on port 3000 +0ms
GET / 304 490.296 ms - -
GET /stylesheets/style.css 200 4.886 ms - 111
```

Enable server restart on file changes
-------------------------------------

Any changes you make to your Express website are currently not visible until you restart the server. It quickly becomes very irritating to have to stop and restart your server every time you make a change, so it is worth taking the time to automate restarting the server when needed.

A convenient tool for this purpose is nodemon. This is usually installed globally (as it is a "tool"), but here we'll install and use it locally as a *developer dependency*, so that any developers working with the project get it automatically when they install the application. Use the following command in the root directory for the skeleton project:

```bash
npm install --save-dev nodemon
```

If you still choose to install nodemon globally to your machine, and not only to your project's **package.json** file:

```bash
npm install -g nodemon
```

If you open your project's **package.json** file you'll now see a new section with this dependency:

```json
 "devDependencies": {
    "nodemon": "^2.0.4"
}
```

Because the tool isn't installed globally we can't launch it from the command line (unless we add it to the path) but we can call it from an npm script because npm knows all about the installed packages. Find the `scripts` section of your package.json. Initially, it will contain one line, which begins with `"start"`. Update it by putting a comma at the end of that line, and adding the `"devstart"` and `"serverstart"` lines:

* On Linux and macOS, the scripts section will look like this:

```json
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www",
    "serverstart": "DEBUG=express-locallibrary-tutorial:\* npm run devstart"
  },
```

* On Windows, the "serverstart" value would instead look like this (if using the command prompt):

```bash
"serverstart": "SET DEBUG=express-locallibrary-tutorial:\* & npm run devstart"
```

We can now start the server in almost exactly the same way as previously, but using the `devstart` command.

**Note:** Now if you edit any file in the project the server will restart (or you can restart it by typing `rs` on the command prompt at any time). You will still need to reload the browser to refresh the page.

We now have to call "`npm run <scriptname>`" rather than just `npm start`, because "start" is actually an npm command that is mapped to the named script. We could have replaced the command in the *start* script but we only want to use *nodemon* during development, so it makes sense to create a new script command.

The `serverstart` command added to the scripts in the **package.json** above is a very good example. Using this approach means you no longer have to type a long command to start the server. Note that the particular command added to the script works for macOS or Linux only.

The generated project
---------------------

Let's now take a look at the project we just created.

### Directory structure

 The generated project, now that you have installed dependencies, has the following file structure (files are the items **not** prefixed with "/").
 The **package.json** file defines the application dependencies and other information.
 It also defines a startup script that will call the application entry point, the JavaScript file **/bin/www**.
 This sets up some of the application error handling and then loads **app.js** to do the rest of the work.
 The app routes are stored in separate modules under the **routes/** directory.
 The templates are stored under the /**views** directory.
```

express-locallibrary-tutorial
    app.js
    /bin
        www
    package.json
    package-lock.json
    /node_modules
        [about 6700 subdirectories and files]
    /public
        /images
        /javascripts
        /stylesheets
            style.css
    /routes
        index.js
        users.js
    /views
        error.pug
        index.pug
        layout.pug
```

The following sections describe the files in a little more detail.

### package.json

The **package.json** file defines the application dependencies and other information:

```json
{
  "name": "express-locallibrary-tutorial",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "morgan": "~1.9.1",
    "pug": "2.0.0-beta11"
  },
  "devDependencies": {
    "nodemon": "^2.0.4"
  }
}
```

The dependencies include the *express* package and the package for our selected view engine (*pug*). In addition, we have the following packages that are useful in many web applications:

* cookie-parser: Used to parse the cookie header and populate `req.cookies` (essentially provides a convenient method for accessing cookie information).
* debug: A tiny node debugging utility modeled after node core's debugging technique.
* morgan: An HTTP request logger middleware for node.
* http-errors: Create HTTP errors where needed (for express error handling).

The scripts section first defines a "*start*" script, which is what we are invoking when we call `npm start` to start the server (this script was added by the *Express Application Generator*). From the script definition, you can see that this actually starts the JavaScript file **./bin/www** with *node*.

```json
  "scripts": {
    "start": "node ./bin/www",
    "devstart": "nodemon ./bin/www",
    "serverstart": "DEBUG=express-locallibrary-tutorial:\* npm run devstart"
  },
```

The *devstart* and *serverstart* scripts can be used to start the same **./bin/www** file with *nodemon* rather than *node* (this example is for Linux and macOS, as discussed above in Enable server restart on file changes).

### www file

The file **/bin/www** is the application entry point! The very first thing this does is `require()` the "real" application entry point (**app.js**, in the project root) that sets up and returns the `express()` application object.

```js
#!/usr/bin/env node

/\*\*
 \* Module dependencies.
 \*/

const app = require("../app");
```

**Note:** `require()` is a global node function that is used to import modules into the current file. Here we specify **app.js** module using a relative path and omitting the optional (.**js**) file extension.

The remainder of the code in this file sets up a node HTTP server with `app` set to a specific port (defined in an environment variable or 3000 if the variable isn't defined), and starts listening and reporting server errors and connections. For now you don't really need to know anything else about the code (everything in this file is "boilerplate"), but feel free to review it if you're interested.

### app.js

This file creates an `express` application object (named `app`, by convention), sets up the application with various settings and middleware, and then exports the app from the module. The code below shows just the parts of the file that create and export the app object:

```js
const express = require("express");
const app = express();
// …
module.exports = app;
```

Back in the **www** entry point file above, it is this `module.exports` object that is supplied to the caller when this file is imported.

Let's work through the **app.js** file in detail. First, we import some useful node libraries into the file using `require()`, including *http-errors*, *express*, *morgan* and *cookie-parser* that we previously downloaded for our application using npm; and *path*, which is a core Node library for parsing file and directory paths.

```js
const createError = require("http-errors");
const express = require("express");
const path = require("path");
const cookieParser = require("cookie-parser");
const logger = require("morgan");
```

Then we `require()` modules from our routes directory. These modules/files contain code for handling particular sets of related "routes" (URL paths). When we extend the skeleton application, for example to list all books in the library, we will add a new file for dealing with book-related routes.

```js
const indexRouter = require("./routes/index");
const usersRouter = require("./routes/users");
```

**Note:** At this point, we have just *imported* the module; we haven't actually used its routes yet (this happens just a little bit further down the file).

Next, we create the `app` object using our imported *express* module, and then use it to set up the view (template) engine. There are two parts to setting up the engine. First, we set the '`views`' value to specify the folder where the templates will be stored (in this case the subfolder **/views**). Then we set the '`view engine`' value to specify the template library (in this case "pug").

```js
const app = express();

// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");
```

 The next set of functions call `app.use()` to add the *middleware* libraries that we imported above into the request handling chain.
 For example, `express.json()` and `express.urlencoded()` are needed to populate `req.body` with the form fields.
 After these libraries we also use the `express.static` middleware, which makes *Express* serve all the static files in the **/public** directory in the project root.

```js
app.use(logger("dev"));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());

app.use(express.static(path.join(__dirname, "public")));
```

Now that all the other middleware is set up, we add our (previously imported) route-handling code to the request handling chain. The imported code will define particular routes for the different *parts* of the site:

```js
app.use("/", indexRouter);
app.use("/users", usersRouter);
```

**Note:** The paths specified above (`'/'` and '`/users'`) are treated as a prefix to routes defined in the imported files.
 So for example, if the imported **users** module defines a route for `/profile`, you would access that route at `/users/profile`. We'll talk more about routes in a later article.

The last middleware in the file adds handler methods for errors and HTTP 404 responses.

```js
// catch 404 and forward to error handler
app.use((req, res, next) => {
  next(createError(404));
});

// error handler
app.use((err, req, res, next) => {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});
```

The Express application object (app) is now fully configured. The last step is to add it to the module exports (this is what allows it to be imported by **/bin/www**).

```js
module.exports = app;
```

### Routes

 The route file **/routes/users.js** is shown below (route files share a similar structure, so we don't need to also show **index.js**).
 First, it loads the *express* module and uses it to get an `express.Router` object.
 Then it specifies a route on that object and lastly exports the router from the module (this is what allows the file to be imported into **app.js**).

```js
const express = require("express");
const router = express.Router();

/\* GET users listing. \*/
router.get("/", (req, res, next) => {
  res.send("respond with a resource");
});

module.exports = router;
```

The route defines a callback that will be invoked whenever an HTTP `GET` request with the correct pattern is detected. The matching pattern is the route specified when the module is imported ('`/users`') plus whatever is defined in this file ('`/`'). In other words, this route will be used when a URL of `/users/` is received.

**Note:** Try this out by running the server with node and visiting the URL in your browser: `http://localhost:3000/users/`. You should see a message: 'respond with a resource'.

One thing of interest above is that the callback function has the third argument '`next`', and is hence a middleware function rather than a simple route callback. While the code doesn't currently use the `next` argument, it may be useful in the future if you want to add multiple route handlers to the `'/'` route path.

### Views (templates)

The views (templates) are stored in the **/views** directory (as specified in **app.js**) and are given the file extension **.pug**. The method `Response.render()` is used to render a specified template along with the values of named variables passed in an object, and then send the result as a response. In the code below from **/routes/index.js** you can see how that route renders a response using the template "index" passing the template variable "title".

```js
/\* GET home page. \*/
router.get("/", (req, res, next) => {
  res.render("index", { title: "Express" });
});
```

The corresponding template for the above route is given below (**index.pug**). We'll talk more about the syntax later. All you need to know for now is that the `title` variable (with value `'Express'`) is inserted where specified in the template.

```pug
extends layout

block content
  h1= title
  p Welcome to #{title}
```

Challenge yourself
------------------

Create a new route in **/routes/users.js** that will display the text "*You're so cool"* at URL `/users/cool/`. Test it by running the server and visiting `http://localhost:3000/users/cool/` in your browser

Summary
-------

You have now created a skeleton website project for the Local Library and verified that it runs using *node*. Most importantly, you also understand how the project is structured, so you have a good idea where we need to make changes to add routes and views for our local library.

Next, we'll start modifying the skeleton so that it works as a library website.

See also
--------

* Express application generator (Express docs)
* Using template engines with Express (Express docs)
* Previous
* Overview: Express Nodejs
* Next


Express Tutorial Part 4: Routes and controllers - Learn web development

Express Tutorial Part 4: Routes and controllers
===============================================

* Previous
* Overview: Express Nodejs
* Next

In this tutorial we'll set up routes (URL handling code) with "dummy" handler functions for all the resource endpoints that we'll eventually need in the LocalLibrary website. On completion we'll have a modular structure for our route handling code, which we can extend with real handler functions in the following articles. We'll also have a really good understanding of how to create modular routes using Express!

|  |  |
| --- | --- |
| Prerequisites: |
 Read the Express/Node introduction.
 Complete previous tutorial topics (including Express Tutorial Part 3: Using a Database (with Mongoose)).
  |
| Objective: |
 To understand how to create simple routes.
 To set up all our URL endpoints.
  |

Overview
--------

In the last tutorial article we defined *Mongoose* models to interact with the database, and used a (standalone) script to create some initial library records. We can now write the code to present that information to users. The first thing we need to do is determine what information we want to be able to display in our pages, and then define appropriate URLs for returning those resources. Then we're going to need to create the routes (URL handlers) and views (templates) to display those pages.

The diagram below is provided as a reminder of the main flow of data and things that need to be implemented when handling an HTTP request/response. In addition to the views and routes the diagram shows "controllers" — functions that separate out the code to route requests from the code that actually processes requests.

As we've already created the models, the main things we'll need to create are:

* "Routes" to forward the supported requests (and any information encoded in request URLs) to the appropriate controller functions.
* Controller functions to get the requested data from the models, create an HTML page displaying the data, and return it to the user to view in the browser.
* Views (templates) used by the controllers to render the data.

![Main data flow diagram of an MVC express server: 'Routes' receive the HTTP requests sent to the Express server and forward them to the appropriate 'controller' function. The controller reads and writes data from the models. Models are connected to the database to provide data access to the server. Controllers use 'views', also called templates, to render the data. The Controller sends the HTML HTTP response back to the client as an HTTP response.](/en-US/docs/Learn/Server-side/Express_Nodejs/routes/mvc_express.png)

Ultimately we might have pages to show lists and detail information for books, genres, authors and bookinstances, along with pages to create, update, and delete records. That's a lot to document in one article. Therefore most of this article will concentrate on setting up our routes and controllers to return "dummy" content. We'll extend the controller methods in our subsequent articles to work with model data.

The first section below provides a brief "primer" on how to use the Express Router middleware. We'll then use that knowledge in the following sections when we set up the LocalLibrary routes.

Routes primer
-------------

A route is a section of Express code that associates an HTTP verb (`GET`, `POST`, `PUT`, `DELETE`, etc.), a URL path/pattern, and a function that is called to handle that pattern.

There are several ways to create routes. For this tutorial we're going to use the `express.Router` middleware as it allows us to group the route handlers for a particular part of a site together and access them using a common route-prefix. We'll keep all our library-related routes in a "catalog" module, and, if we add routes for handling user accounts or other functions, we can keep them grouped separately.

**Note:** We discussed Express application routes briefly in our Express Introduction > Creating route handlers. Other than providing better support for modularization (as discussed in the first subsection below), using *Router* is very similar to defining routes directly on the *Express application object*.

The rest of this section provides an overview of how the `Router` can be used to define the routes.

### Defining and using separate route modules

The code below provides a concrete example of how we can create a route module and then use it in an *Express* application.

First we create routes for a wiki in a module named **wiki.js**. The code first imports the Express application object, uses it to get a `Router` object and then adds a couple of routes to it using the `get()` method. Last of all the module exports the `Router` object.

```js
// wiki.js - Wiki route module.

const express = require("express");
const router = express.Router();

// Home page route.
router.get("/", function (req, res) {
  res.send("Wiki home page");
});

// About page route.
router.get("/about", function (req, res) {
  res.send("About this wiki");
});

module.exports = router;
```

**Note:** Above we are defining our route handler callbacks directly in the router functions. In the LocalLibrary we'll define these callbacks in a separate controller module.

To use the router module in our main app file we first `require()` the route module (**wiki.js**). We then call `use()` on the *Express* application to add the Router to the middleware handling path, specifying a URL path of 'wiki'.

```js
const wiki = require("./wiki.js");
// …
app.use("/wiki", wiki);
```

The two routes defined in our wiki route module are then accessible from `/wiki/` and `/wiki/about/`.

### Route functions

Our module above defines a couple of typical route functions. The "about" route (reproduced below) is defined using the `Router.get()` method, which responds only to HTTP GET requests. The first argument to this method is the URL path while the second is a callback function that will be invoked if an HTTP GET request with the path is received.

```js
router.get("/about", function (req, res) {
  res.send("About this wiki");
});
```

The callback takes three arguments (usually named as shown: `req`, `res`, `next`), that will contain the HTTP Request object, HTTP response, and the *next* function in the middleware chain.

**Note:** Router functions are Express middleware, which means that they must either complete (respond to) the request or call the `next` function in the chain. In the case above we complete the request using `send()`, so the `next` argument is not used (and we choose not to specify it).

The router function above takes a single callback, but you can specify as many callback arguments as you want, or an array of callback functions. Each function is part of the middleware chain, and will be called in the order it is added to the chain (unless a preceding function completes the request).

The callback function here calls `send()` on the response to return the string "About this wiki" when we receive a GET request with the path ('`/about'`). There are a number of other response methods for ending the request/response cycle. For example, you could call `res.json()` to send a JSON response or `res.sendFile()` to send a file. The response method that we'll be using most often as we build up the library is render(), which creates and returns HTML files using templates and data—we'll talk a lot more about that in a later article!

### HTTP verbs

The example routes above use the `Router.get()` method to respond to HTTP GET requests with a certain path.

The `Router` also provides route methods for all the other HTTP verbs, that are mostly used in exactly the same way: `post()`, `put()`, `delete()`, `options()`, `trace()`, `copy()`, `lock()`, `mkcol()`, `move()`, `purge()`, `propfind()`, `proppatch()`, `unlock()`, `report()`, `mkactivity()`, `checkout()`, `merge()`, `m-search()`, `notify()`, `subscribe()`, `unsubscribe()`, `patch()`, `search()`, and `connect()`.

For example, the code below behaves just like the previous `/about` route, but only responds to HTTP POST requests.

```js
router.post("/about", (req, res) => {
  res.send("About this wiki");
});
```

### Route paths

The route paths define the endpoints at which requests can be made. The examples we've seen so far have just been strings, and are used exactly as written: '/', '/about', '/book', '/any-random.path'.

Route paths can also be string patterns. String patterns use a form of regular expression syntax to define *patterns* of endpoints that will be matched. The syntax is listed below (note that the hyphen (`-`) and the dot (`.`) are interpreted literally by string-based paths):

* `?` : The endpoint must have 0 or 1 of the preceding character (or group), e.g. a route path of `'/ab?cd'` will match endpoints `acd` or `abcd`.
* `+` : The endpoint must have 1 or more of the preceding character (or group), e.g. a route path of `'/ab+cd'` will match endpoints `abcd`, `abbcd`, `abbbcd`, and so on.
* `*` : The endpoint may have an arbitrary string where the `*` character is placed. E.g. a route path of `'/ab*cd'` will match endpoints `abcd`, `abXcd`, `abSOMErandomTEXTcd`, and so on.
* `()` : Grouping match on a set of characters to perform another operation on, e.g. `'/ab(cd)?e'` will perform a `?`-match on the group `(cd)` — it will match `abe` and `abcde`.

The route paths can also be JavaScript regular expressions. For example, the route path below will match `catfish` and `dogfish`, but not `catflap`, `catfishhead`, and so on. Note that the path for a regular expression uses regular expression syntax (it is not a quoted string as in the previous cases).

```js
app.get(/.\*fish$/, function (req, res) {
  // …
});
```

**Note:** Most of our routes for the LocalLibrary will use strings and not regular expressions. We'll also use route parameters as discussed in the next section.

### Route parameters

Route parameters are *named URL segments* used to capture values at specific positions in the URL. The named segments are prefixed with a colon and then the name (E.g., `/:your_parameter_name/`). The captured values are stored in the `req.params` object using the parameter names as keys (E.g., `req.params.your_parameter_name`).

So for example, consider a URL encoded to contain information about users and books: `http://localhost:3000/users/34/books/8989`. We can extract this information as shown below, with the `userId` and `bookId` path parameters:

```js
app.get("/users/:userId/books/:bookId", (req, res) => {
  // Access userId via: req.params.userId
  // Access bookId via: req.params.bookId
  res.send(req.params);
});
```

The names of route parameters must be made up of "word characters" (A-Z, a-z, 0-9, and \_).

**Note:** The URL */book/create* will be matched by a route like `/book/:bookId` (because `:bookId` is a placeholder for *any* string, therefore `create` matches). The first route that matches an incoming URL will be used, so if you want to process `/book/create` URLs specifically, their route handler must be defined before your `/book/:bookId` route.

That's all you need to get started with routes - if needed you can find more information in the Express docs: Basic routing and Routing guide. The following sections show how we'll set up our routes and controllers for the LocalLibrary.

### Handling errors in the route functions

 The route functions shown earlier all have arguments `req` and `res`, which represent the request and response, respectively.
 Route functions are also called with a third argument `next`, which can be used to pass errors to the Express middleware chain.

 The code below shows how this works, using the example of a database query that takes a callback function, and returns either an error `err` or some results.
 If `err` is returned, `next` is called with `err` as the value in its first parameter (eventually the error propagates to our global error handling code).
 On success the desired data is returned and then used in the response.

```js
router.get("/about", (req, res, next) => {
  About.find({}).exec((err, queryResults) => {
    if (err) {
      return next(err);
    }
    //Successful, so render
    res.render("about\_view", { title: "About", list: queryResults });
  });
});
```

### Handling exceptions in route functions

 The previous section shows how Express expects route functions to return errors.
 The framework is designed for use with asynchronous functions that take a callback function (with an error and result argument), which is called when the operation completes.
 That's a problem because later on we will be making Mongoose database queries that use Promise-based APIs, and which may throw exceptions in our route functions (rather than returning errors in a callback).

In order for the framework to properly handle exceptions, they must be caught, and then forwarded as errors as shown in the previous section.

**Note:** Express 5, which is currently in beta, is expected to handle JavaScript exceptions natively.

Re-imagining the simple example from the previous section with `About.find().exec()` as a database query that returns a promise, we might write the route function inside a `try...catch` block like this:

```js
exports.get("/about", async function (req, res, next) {
  try {
    const successfulResult = await About.find({}).exec();
    res.render("about\_view", { title: "About", list: successfulResult });
  } catch (error) {
    return next(error);
  }
});
```

 That's quite a lot of boilerplate code to add to every function.
 Instead, for this tutorial we'll use the express-async-handler module.
 This defines a wrapper function that hides the `try...catch` block and the code to forward the error.
 The same example is now very simple, because we only need to write code for the case where we assume success:

```js
// Import the module
const asyncHandler = require("express-async-handler");

exports.get(
  "/about",
  asyncHandler(async (req, res, next) => {
    const successfulResult = await About.find({}).exec();
    res.render("about\_view", { title: "About", list: successfulResult });
  }),
);
```

Routes needed for the LocalLibrary
----------------------------------

The URLs that we're ultimately going to need for our pages are listed below, where *object* is replaced by the name of each of our models (book, bookinstance, genre, author), *objects* is the plural of object, and *id* is the unique instance field (`_id`) that is given to each Mongoose model instance by default.

* `catalog/` — The home/index page.
* `catalog/<objects>/` — The list of all books, bookinstances, genres, or authors (e.g. /`catalog/books/`, /`catalog/genres/`, etc.)
* `catalog/<object>/<id>` — The detail page for a specific book, bookinstance, genre, or author with the given `_id` field value (e.g. `/catalog/book/584493c1f4887f06c0e67d37)`.
* `catalog/<object>/create` — The form to create a new book, bookinstance, genre, or author (e.g. `/catalog/book/create)`.
* `catalog/<object>/<id>/update` — The form to update a specific book, bookinstance, genre, or author with the given `_id` field value (e.g. `/catalog/book/584493c1f4887f06c0e67d37/update)`.
* `catalog/<object>/<id>/delete` — The form to delete a specific book, bookinstance, genre, author with the given `_id` field value (e.g. `/catalog/book/584493c1f4887f06c0e67d37/delete)`.

The first home page and list pages don't encode any additional information. While the results returned will depend on the model type and the content in the database, the queries run to get the information will always be the same (similarly the code run for object creation will always be similar).

By contrast the other URLs are used to act on a specific document/model instance—these encode the identity of the item in the URL (shown as `<id>` above). We'll use path parameters to extract the encoded information and pass it to the route handler (and in a later article we'll use this to dynamically determine what information to get from the database). By encoding the information in our URL we only need one route for every resource of a particular type (e.g. one route to handle the display of every single book item).

**Note:** Express allows you to construct your URLs any way you like — you can encode information in the body of the URL as shown above or use URL `GET` parameters (e.g. `/book/?id=6`). Whichever approach you use, the URLs should be kept clean, logical and readable (check out the W3C advice here).

Next we create our route handler callback functions and route code for all the above URLs.

Create the route-handler callback functions
-------------------------------------------

Before we define our routes, we'll first create all the dummy/skeleton callback functions that they will invoke. The callbacks will be stored in separate "controller" modules for `Book`, `BookInstance`, `Genre`, and `Author` (you can use any file/module structure, but this seems an appropriate granularity for this project).

Start by creating a folder for our controllers in the project root (**/controllers**) and then create separate controller files/modules for handling each of the models:
```

/express-locallibrary-tutorial  //the project root
  /controllers
    authorController.js
    bookController.js
    bookinstanceController.js
    genreController.js
```

The controllers will use the `express-async-handler` module, so before we proceed, install it into the library using `npm`:

```bash
npm install express-async-handler
```

### Author controller

Open the **/controllers/authorController.js** file and type in the following code:

```js
const Author = require("../models/author");
const asyncHandler = require("express-async-handler");

// Display list of all Authors.
exports.author_list = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author list");
});

// Display detail page for a specific Author.
exports.author_detail = asyncHandler(async (req, res, next) => {
  res.send(`NOT IMPLEMENTED: Author detail: ${req.params.id}`);
});

// Display Author create form on GET.
exports.author_create_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author create GET");
});

// Handle Author create on POST.
exports.author_create_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author create POST");
});

// Display Author delete form on GET.
exports.author_delete_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author delete GET");
});

// Handle Author delete on POST.
exports.author_delete_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author delete POST");
});

// Display Author update form on GET.
exports.author_update_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author update GET");
});

// Handle Author update on POST.
exports.author_update_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Author update POST");
});
```

 The module first requires the `Author` model that we'll later be using to access and update our data, and the `asyncHandler` wrapper we'll use to catch any exceptions thrown in our route handler functions.
 It then exports functions for each of the URLs we wish to handle.
 Note that the create, update and delete operations use forms, and hence also have additional methods for handling form post requests — we'll discuss those methods in the "forms article" later on.

 The functions all use the wrapper function described above in Handling exceptions in route functions, with arguments for the request, response, and next.
 The functions respond with a string indicating that the associated page has not yet been created.
 If a controller function is expected to receive path parameters, these are output in the message string (see `req.params.id` above).

 Note that once implemented, some route functions might not contain any code that can throw exceptions.
 We can change those back to "normal" route handler functions when we get to them.

#### BookInstance controller

Open the **/controllers/bookinstanceController.js** file and copy in the following code (this follows an identical pattern to the `Author` controller module):

```js
const BookInstance = require("../models/bookinstance");
const asyncHandler = require("express-async-handler");

// Display list of all BookInstances.
exports.bookinstance_list = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance list");
});

// Display detail page for a specific BookInstance.
exports.bookinstance_detail = asyncHandler(async (req, res, next) => {
  res.send(`NOT IMPLEMENTED: BookInstance detail: ${req.params.id}`);
});

// Display BookInstance create form on GET.
exports.bookinstance_create_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance create GET");
});

// Handle BookInstance create on POST.
exports.bookinstance_create_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance create POST");
});

// Display BookInstance delete form on GET.
exports.bookinstance_delete_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance delete GET");
});

// Handle BookInstance delete on POST.
exports.bookinstance_delete_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance delete POST");
});

// Display BookInstance update form on GET.
exports.bookinstance_update_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance update GET");
});

// Handle bookinstance update on POST.
exports.bookinstance_update_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: BookInstance update POST");
});
```

#### Genre controller

Open the **/controllers/genreController.js** file and copy in the following text (this follows an identical pattern to the `Author` and `BookInstance` files):

```js
const Genre = require("../models/genre");
const asyncHandler = require("express-async-handler");

// Display list of all Genre.
exports.genre_list = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre list");
});

// Display detail page for a specific Genre.
exports.genre_detail = asyncHandler(async (req, res, next) => {
  res.send(`NOT IMPLEMENTED: Genre detail: ${req.params.id}`);
});

// Display Genre create form on GET.
exports.genre_create_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre create GET");
});

// Handle Genre create on POST.
exports.genre_create_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre create POST");
});

// Display Genre delete form on GET.
exports.genre_delete_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre delete GET");
});

// Handle Genre delete on POST.
exports.genre_delete_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre delete POST");
});

// Display Genre update form on GET.
exports.genre_update_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre update GET");
});

// Handle Genre update on POST.
exports.genre_update_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Genre update POST");
});
```

#### Book controller

 Open the **/controllers/bookController.js** file and copy in the following code.
 This follows the same pattern as the other controller modules, but additionally has an `index()` function for displaying the site welcome page:

```js
const Book = require("../models/book");
const asyncHandler = require("express-async-handler");

exports.index = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Site Home Page");
});

// Display list of all books.
exports.book_list = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book list");
});

// Display detail page for a specific book.
exports.book_detail = asyncHandler(async (req, res, next) => {
  res.send(`NOT IMPLEMENTED: Book detail: ${req.params.id}`);
});

// Display book create form on GET.
exports.book_create_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book create GET");
});

// Handle book create on POST.
exports.book_create_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book create POST");
});

// Display book delete form on GET.
exports.book_delete_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book delete GET");
});

// Handle book delete on POST.
exports.book_delete_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book delete POST");
});

// Display book update form on GET.
exports.book_update_get = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book update GET");
});

// Handle book update on POST.
exports.book_update_post = asyncHandler(async (req, res, next) => {
  res.send("NOT IMPLEMENTED: Book update POST");
});
```

Create the catalog route module
-------------------------------

Next we create *routes* for all the URLs needed by the LocalLibrary website, which will call the controller functions we defined in the previous sections.

 The skeleton already has a **./routes** folder containing routes for the *index* and *users*.
 Create another route file — **catalog.js** — inside this folder, as shown.
```

/express-locallibrary-tutorial //the project root
  /routes
    index.js
    users.js
    catalog.js
```

Open **/routes/catalog.js** and copy in the code below:

```js
const express = require("express");
const router = express.Router();

// Require controller modules.
const book_controller = require("../controllers/bookController");
const author_controller = require("../controllers/authorController");
const genre_controller = require("../controllers/genreController");
const book_instance_controller = require("../controllers/bookinstanceController");

/// BOOK ROUTES ///

// GET catalog home page.
router.get("/", book_controller.index);

// GET request for creating a Book. NOTE This must come before routes that display Book (uses id).
router.get("/book/create", book_controller.book_create_get);

// POST request for creating Book.
router.post("/book/create", book_controller.book_create_post);

// GET request to delete Book.
router.get("/book/:id/delete", book_controller.book_delete_get);

// POST request to delete Book.
router.post("/book/:id/delete", book_controller.book_delete_post);

// GET request to update Book.
router.get("/book/:id/update", book_controller.book_update_get);

// POST request to update Book.
router.post("/book/:id/update", book_controller.book_update_post);

// GET request for one Book.
router.get("/book/:id", book_controller.book_detail);

// GET request for list of all Book items.
router.get("/books", book_controller.book_list);

/// AUTHOR ROUTES ///

// GET request for creating Author. NOTE This must come before route for id (i.e. display author).
router.get("/author/create", author_controller.author_create_get);

// POST request for creating Author.
router.post("/author/create", author_controller.author_create_post);

// GET request to delete Author.
router.get("/author/:id/delete", author_controller.author_delete_get);

// POST request to delete Author.
router.post("/author/:id/delete", author_controller.author_delete_post);

// GET request to update Author.
router.get("/author/:id/update", author_controller.author_update_get);

// POST request to update Author.
router.post("/author/:id/update", author_controller.author_update_post);

// GET request for one Author.
router.get("/author/:id", author_controller.author_detail);

// GET request for list of all Authors.
router.get("/authors", author_controller.author_list);

/// GENRE ROUTES ///

// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
router.get("/genre/create", genre_controller.genre_create_get);

//POST request for creating Genre.
router.post("/genre/create", genre_controller.genre_create_post);

// GET request to delete Genre.
router.get("/genre/:id/delete", genre_controller.genre_delete_get);

// POST request to delete Genre.
router.post("/genre/:id/delete", genre_controller.genre_delete_post);

// GET request to update Genre.
router.get("/genre/:id/update", genre_controller.genre_update_get);

// POST request to update Genre.
router.post("/genre/:id/update", genre_controller.genre_update_post);

// GET request for one Genre.
router.get("/genre/:id", genre_controller.genre_detail);

// GET request for list of all Genre.
router.get("/genres", genre_controller.genre_list);

/// BOOKINSTANCE ROUTES ///

// GET request for creating a BookInstance. NOTE This must come before route that displays BookInstance (uses id).
router.get(
  "/bookinstance/create",
  book_instance_controller.bookinstance_create_get,
);

// POST request for creating BookInstance.
router.post(
  "/bookinstance/create",
  book_instance_controller.bookinstance_create_post,
);

// GET request to delete BookInstance.
router.get(
  "/bookinstance/:id/delete",
  book_instance_controller.bookinstance_delete_get,
);

// POST request to delete BookInstance.
router.post(
  "/bookinstance/:id/delete",
  book_instance_controller.bookinstance_delete_post,
);

// GET request to update BookInstance.
router.get(
  "/bookinstance/:id/update",
  book_instance_controller.bookinstance_update_get,
);

// POST request to update BookInstance.
router.post(
  "/bookinstance/:id/update",
  book_instance_controller.bookinstance_update_post,
);

// GET request for one BookInstance.
router.get("/bookinstance/:id", book_instance_controller.bookinstance_detail);

// GET request for list of all BookInstance.
router.get("/bookinstances", book_instance_controller.bookinstance_list);

module.exports = router;
```

The module requires Express and then uses it to create a `Router` object. The routes are all set up on the router, which is then exported.

 The routes are defined either using `.get()` or `.post()` methods on the router object. All the paths are defined using strings (we don't use string patterns or regular expressions).
 Routes that act on some specific resource (e.g. book) use path parameters to get the object id from the URL.

The handler functions are all imported from the controller modules we created in the previous section.

### Update the index route module

We've set up all our new routes, but we still have a route to the original page. Let's instead redirect this to the new index page that we've created at the path '/catalog'.

Open **/routes/index.js** and replace the existing route with the function below.

```js
// GET home page.
router.get("/", function (req, res) {
  res.redirect("/catalog");
});
```

**Note:** This is our first use of the redirect() response method. This redirects to the specified page, by default sending HTTP status code "302 Found". You can change the status code returned if needed, and supply either absolute or relative paths.

### Update app.js

 The last step is to add the routes to the middleware chain.
 We do this in `app.js`.

Open **app.js** and require the catalog route below the other routes (add the third line shown below, underneath the other two that should be already present in the file):

```js
var indexRouter = require("./routes/index");
var usersRouter = require("./routes/users");
const catalogRouter = require("./routes/catalog"); //Import routes for "catalog" area of site
```

Next, add the catalog route to the middleware stack below the other routes (add the third line shown below, underneath the other two that should be already present in the file):

```js
app.use("/", indexRouter);
app.use("/users", usersRouter);
app.use("/catalog", catalogRouter); // Add catalog routes to middleware chain.
```

**Note:** We have added our catalog module at a path `'/catalog'`. This is prepended to all of the paths defined in the catalog module. So for example, to access a list of books, the URL will be: `/catalog/books/`.

That's it. We should now have routes and skeleton functions enabled for all the URLs that we will eventually support on the LocalLibrary website.

### Testing the routes

To test the routes, first start the website using your usual approach

* The default method

```bash
// Windows
SET DEBUG=express-locallibrary-tutorial:* & npm start

// macOS or Linux
DEBUG=express-locallibrary-tutorial:* npm start
```

* If you previously set up nodemon, you can instead use:

```bash
npm run serverstart
```

Then navigate to a number of LocalLibrary URLs, and verify that you don't get an error page (HTTP 404). A small set of URLs are listed below for your convenience:

* `http://localhost:3000/`
* `http://localhost:3000/catalog`
* `http://localhost:3000/catalog/books`
* `http://localhost:3000/catalog/bookinstances/`
* `http://localhost:3000/catalog/authors/`
* `http://localhost:3000/catalog/genres/`
* `http://localhost:3000/catalog/book/5846437593935e2f8c2aa226`
* `http://localhost:3000/catalog/book/create`
Summary
-------

We've now created all the routes for our site, along with dummy controller functions that we can populate with a full implementation in later articles. Along the way we've learned a lot of fundamental information about Express routes, handling exceptions, and some approaches for structuring our routes and controllers.

In our next article we'll create a proper welcome page for the site, using views (templates) and information stored in our models.

See also
--------

* Basic routing (Express docs)
* Routing guide (Express docs)
* Previous
* Overview: Express Nodejs
* Next


Express Tutorial Part 6: Working with forms - Learn web development

Express Tutorial Part 6: Working with forms
===========================================

* Previous
* Overview: Express Nodejs
* Next

In this tutorial we'll show you how to work with HTML Forms in Express using Pug. In particular, we'll discuss how to write forms to create, update, and delete documents from the site's database.

|  |  |
| --- | --- |
| Prerequisites: | Complete all previous tutorial topics, including Express Tutorial Part 5: Displaying library data |
| Objective: | To understand how to write forms to get data from users, and update the database with this data. |

Overview
--------

An HTML Form is a group of one or more fields/widgets on a web page that can be used to collect information from users for submission to a server. Forms are a flexible mechanism for collecting user input because there are suitable form inputs available for entering many different types of data—text boxes, checkboxes, radio buttons, date pickers, etc. Forms are also a relatively secure way of sharing data with the server, as they allow us to send data in `POST` requests with cross-site request forgery protection.

Working with forms can be complicated! Developers need to write HTML for the form, validate and properly sanitize entered data on the server (and possibly also in the browser), repost the form with error messages to inform users of any invalid fields, handle the data when it has successfully been submitted, and finally respond to the user in some way to indicate success.

In this tutorial, we're going to show you how the above operations may be performed in *Express*. Along the way, we'll extend the *LocalLibrary* website to allow users to create, edit and delete items from the library.

**Note:** We haven't looked at how to restrict particular routes to authenticated or authorized users, so at this point, any user will be able to make changes to the database.

### HTML Forms

First a brief overview of HTML Forms. Consider a simple HTML form, with a single text field for entering the name of some "team", and its associated label:

![Simple name field example in HTML form](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/form_example_name_field.png)

The form is defined in HTML as a collection of elements inside `<form>…</form>` tags, containing at least one `input` element of `type="submit"`.

```html
<form action="/team\_name\_url/" method="post">
  <label for="team\_name">Enter name: </label>
  <input
 id="team\_name"
 type="text"
 name="name\_field"
 value="Default name for team." />
  <input type="submit" value="OK" />
</form>
```

While here we have included just one (text) field for entering the team name, a form *may* contain any number of other input elements and their associated labels. The field's `type` attribute defines what sort of widget will be displayed. The `name` and `id` of the field are used to identify the field in JavaScript/CSS/HTML, while `value` defines the initial value for the field when it is first displayed. The matching team label is specified using the `label` tag (see "Enter name" above), with a `for` field containing the `id` value of the associated `input`.

The `submit` input will be displayed as a button (by default)—this can be pressed by the user to upload the data contained by the other input elements to the server (in this case, just the `team_name`). The form attributes define the HTTP `method` used to send the data and the destination of the data on the server (`action`):

* `action`: The resource/URL where data is to be sent for processing when the form is submitted. If this is not set (or set to an empty string), then the form will be submitted back to the current page URL.
* `method`: The HTTP method used to send the data: `POST` or `GET`.
    + The `POST` method should always be used if the data is going to result in a change to the server's database, because this can be made more resistant to cross-site forgery request attacks.
    + The `GET` method should only be used for forms that don't change user data (e.g. a search form). It is recommended for when you want to be able to bookmark or share the URL.
### Form handling process

Form handling uses all of the same techniques that we learned for displaying information about our models: the route sends our request to a controller function which performs any database actions required, including reading data from the models, then generates and returns an HTML page. What makes things more complicated is that the server also needs to be able to process the data provided by the user, and redisplay the form with error information if there are any problems.

A process flowchart for processing form requests is shown below, starting with a request for a page containing a form (shown in green):

![Web server form request processing flowchart. Browser requests for the page containing the form by sending an HTTP GET request. The server creates an empty default form and returns it to the user. The user populates or updates the form, submitting it via HTTP POST with form data. The server validates the received form data. If the user-provided data is invalid, the server recreates the form with the user-entered data and error messages and sends it back to the user for the user to update and resubmits via HTTP Post, and it validates again. If the data is valid, the server performs actions on the valid data and redirects the user to the success URL.](/en-US/docs/Learn/Server-side/Express_Nodejs/forms/web_server_form_handling.png)

As shown in the diagram above, the main things that form handling code needs to do are:

1. Display the default form the first time it is requested by the user.
    * The form may contain blank fields (e.g. if you're creating a new record), or it may be pre-populated with initial values (e.g. if you are changing a record, or have useful default initial values).
2. Receive data submitted by the user, usually in an HTTP `POST` request.
3. Validate and sanitize the data.
4. If any data is invalid, re-display the form—this time with any user populated values and error messages for the problem fields.
5. If all data is valid, perform required actions (e.g. save the data in the database, send a notification email, return the result of a search, upload a file, etc.)
6. Once all actions are complete, redirect the user to another page.

Often form handling code is implemented using a `GET` route for the initial display of the form and a `POST` route to the same path for handling validation and processing of form data. This is the approach that will be used in this tutorial.

Express itself doesn't provide any specific support for form handling operations, but it can use middleware to process `POST` and `GET` parameters from the form, and to validate/sanitize their values.

### Validation and sanitization

Before the data from a form is stored it must be validated and sanitized:

* Validation checks that entered values are appropriate for each field (are in the right range, format, etc.) and that values have been supplied for all required fields.
* Sanitization removes/replaces characters in the data that might potentially be used to send malicious content to the server.

For this tutorial, we'll be using the popular express-validator module to perform both validation and sanitization of our form data.

#### Installation

Install the module by running the following command in the root of the project.

```bash
npm install express-validator
```

#### Using express-validator

**Note:** The express-validator guide on GitHub provides a good overview of the API. We recommend you read that to get an idea of all its capabilities (including using schema validation and creating custom validators). Below we cover just a subset that is useful for the *LocalLibrary*.

To use the validator in our controllers, we specify the particular functions we want to import from the express-validator module, as shown below:

```js
const { body, validationResult } = require("express-validator");
```

There are many functions available, allowing you to check and sanitize data from request parameters, body, headers, cookies, etc., or all of them at once. For this tutorial, we'll primarily be using `body` and `validationResult` (as "required" above).

The functions are defined as below:

* `body([fields, message])`: Specifies a set of fields in the request body (a `POST` parameter) to validate and/or sanitize along with an optional error message that can be displayed if it fails the tests. The validation and sanitize criteria are daisy-chained to the `body()` method.
 For example, the line below first defines that we're checking the "name" field and that a validation error will set an error message "Empty name". We then call the sanitization method `trim()` to remove whitespace from the start and end of the string, and then `isLength()` to check the resulting string isn't empty. Finally, we call `escape()` to remove HTML characters from the variable that might be used in JavaScript cross-site scripting attacks.

```js
[
  // …
  body("name", "Empty name").trim().isLength({ min: 1 }).escape(),
  // …
];
```

This test checks that the age field is a valid date and uses `optional()` to specify that null and empty strings will not fail validation.

```js
[
  // …
  body("age", "Invalid age")
    .optional({ values: "falsy" })
    .isISO8601()
    .toDate(),
  // …
];
```

You can also daisy chain different validators, and add messages that are displayed if the preceding validators are false.

```js
[
  // …
  body("name")
    .trim()
    .isLength({ min: 1 })
    .withMessage("Name empty.")
    .isAlpha()
    .withMessage("Name must be alphabet letters."),
  // …
];
```

* `validationResult(req)`: Runs the validation, making errors available in the form of a `validation` result object. This is invoked in a separate callback, as shown below:

```js
asyncHandler(async (req, res, next) => {
  // Extract the validation errors from a request.
  const errors = validationResult(req);

  if (!errors.isEmpty()) {
    // There are errors. Render form again with sanitized values/errors messages.
    // Error messages can be returned in an array using `errors.array()`.
  } else {
    // Data from form is valid.
  }
});
```

We use the validation result's `isEmpty()` method to check if there were errors, and its `array()` method to get the set of error messages. See the Handling validation section for more information.

The validation and sanitization chains are middleware that should be passed to the Express route handler (we do this indirectly, via the controller). When the middleware runs, each validator/sanitizer is run in the order specified.

We'll cover some real examples when we implement the *LocalLibrary* forms below.

### Form design

Many of the models in the library are related/dependent—for example, a `Book` *requires* an `Author`, and *may* also have one or more `Genres`. This raises the question of how we should handle the case where a user wishes to:

* Create an object when its related objects do not yet exist (for example, a book where the author object hasn't been defined).
* Delete an object that is still being used by another object (so for example, deleting a `Genre` that is still being used by a `Book`).

For this project we will simplify the implementation by stating that a form can only:

* Create an object using objects that already exist (so users will have to create any required `Author` and `Genre` instances before attempting to create any `Book` objects).
* Delete an object if it is not referenced by other objects (so for example, you won't be able to delete a `Book` until all associated `BookInstance` objects have been deleted).

**Note:** A more flexible implementation might allow you to create the dependent objects when creating a new object, and delete any object at any time (for example, by deleting dependent objects, or by removing references to the deleted object from the database).

### Routes

In order to implement our form handling code, we will need two routes that have the same URL pattern. The first (`GET`) route is used to display a new empty form for creating the object. The second route (`POST`) is used for validating data entered by the user, and then saving the information and redirecting to the detail page (if the data is valid) or redisplaying the form with errors (if the data is invalid).

We have already created the routes for all our model's create pages in **/routes/catalog.js** (in a previous tutorial). For example, the genre routes are shown below:

```js
// GET request for creating a Genre. NOTE This must come before route that displays Genre (uses id).
router.get("/genre/create", genre_controller.genre_create_get);

// POST request for creating Genre.
router.post("/genre/create", genre_controller.genre_create_post);
```

Express forms subarticles
-------------------------

The following sub articles will take us through the process of adding the required forms to our example application. You need to read and work through each one in turn, before moving on to the next one.

1. Create Genre form — Defining a page to create `Genre` objects.
2. Create Author form — Defining a page to create `Author` objects.
3. Create Book form — Defining a page/form to create `Book` objects.
4. Create BookInstance form — Defining a page/form to create `BookInstance` objects.
5. Delete Author form — Defining a page to delete `Author` objects.
6. Update Book form — Defining page to update `Book` objects.
Challenge yourself
------------------

Implement the delete pages for the `Book`, `BookInstance`, and `Genre` models, linking them from the associated detail pages in the same way as our *Author delete* page. The pages should follow the same design approach:

* If there are references to the object from other objects, then these other objects should be displayed along with a note that this record can't be deleted until the listed objects have been deleted.
* If there are no other references to the object then the view should prompt to delete it. If the user presses the **Delete** button, the record should then be deleted.

A few tips:

* Deleting a `Genre` is just like deleting an `Author`, as both objects are dependencies of `Book` (so in both cases you can delete the object only when the associated books are deleted).
* Deleting a `Book` is also similar as you need to first check that there are no associated `BookInstances`.
* Deleting a `BookInstance` is the easiest of all because there are no dependent objects. In this case, you can just find the associated record and delete it.

Implement the update pages for the `BookInstance`, `Author`, and `Genre` models, linking them from the associated detail pages in the same way as our *Book update* page.

A few tips:

* The *Book update page* we just implemented is the hardest! The same patterns can be used for the update pages for the other objects.
* The `Author` date of death and date of birth fields and the `BookInstance` due\_date field are the wrong format to input into the date input field on the form (it requires data in form "YYYY-MM-DD"). The easiest way to get around this is to define a new virtual property for the dates that formats the dates appropriately, and then use this field in the associated view templates.
* If you get stuck, there are examples of the update pages in the example here.
Summary
-------

*Express*, node, and third-party packages on npm provide everything you need to add forms to your website. In this article, you've learned how to create forms using *Pug*, validate and sanitize input using *express-validator*, and add, delete, and modify records in the database.

You should now understand how to add basic forms and form-handling code to your own node websites!

See also
--------

* express-validator (npm docs).
* Previous
* Overview: Express Nodejs
* Next


Setting up a Node development environment - Learn web development

Setting up a Node development environment
=========================================

* Previous
* Overview: Express Nodejs
* Next

Now that you know what Express is for, we'll show you how to set up and test a Node/Express development environment on Windows, or Linux (Ubuntu), or macOS. For any of those operating systems, this article provides what you need to start developing Express apps.

|  |  |
| --- | --- |
| Prerequisites: | Know how to open a terminal / command line. Know how to install software packages on your development computer's operating system. |
| Objective: | To set up a development environment for Express on your computer. |

Express development environment overview
----------------------------------------

*Node* and *Express* make it very easy to set up your computer in order to start developing web applications. This section provides an overview of what tools are needed, explains some of the simplest methods for installing Node (and Express) on Ubuntu, macOS, and Windows, and shows how you can test your installation.

### What is the Express development environment?

The *Express* development environment includes an installation of *Nodejs*, the *npm package manager*, and (optionally) the *Express Application Generator* on your local computer.

*Node* and the *npm* package manager are installed together from prepared binary packages, installers, operating system package managers or from source (as shown in the following sections). *Express* is then installed by npm as a dependency of your individual *Express* web applications (along with other libraries like template engines, database drivers, authentication middleware, middleware to serve static files, etc.).

*npm* can also be used to (globally) install the *Express Application Generator*, a handy tool for creating skeleton *Express* web apps that follow the MVC pattern. The application generator is optional because you don't *need* to use this tool to create apps that use Express, or construct Express apps that have the same architectural layout or dependencies. We'll be using it though, because it makes getting started a lot easier, and promotes a modular application structure.

**Note:** Unlike some other web frameworks, the development environment does not include a separate development web server. In *Node*/*Express* a web application creates and runs its own web server!

There are other peripheral tools that are part of a typical development environment, including text editors or IDEs for editing code, and source control management tools like Git for safely managing different versions of your code. We are assuming that you've already got these sorts of tools installed (in particular a text editor).

### What operating systems are supported?

*Node* can be run on Windows, macOS, many flavors of Linux, Docker, etc. There is a full list on the Node.js Downloads page. Almost any personal computer should have the necessary performance to run Node during development. *Express* is run in a *Node* environment, and hence can run on any platform that runs *Node*.

In this article we provide setup instructions for Windows, macOS, and Ubuntu Linux.

### What version of Node/Express should you use?

There are many releases of Node — newer releases contain bug fixes, support for more recent versions of ECMAScript (JavaScript) standards, and improvements to the Node APIs.

Generally you should use the most recent *LTS (long-term supported)* release as this will be more stable than the "current" release while still having relatively recent features (and is still being actively maintained). You should use the *Current* release if you need a feature that is not present in the LTS version.

For *Express* you should always use the latest version.

### What about databases and other dependencies?

Other dependencies, such as database drivers, template engines, authentication engines, etc. are part of the application, and are imported into the application environment using the npm package manager. We'll discuss them in later app-specific articles.

Installing Node
---------------

 In order to use *Express* you will have to install *Nodejs* and the Node Package Manager (npm) on your operating system.
 To make this easier we'll first install a node version manager, and then we'll use it to install the latest Long Term Supported (LTS) versions of node and npm.

**Note:** You can also install nodejs and npm with installers provide on https://nodejs.org/en/ (select the button to download the LTS build that is "Recommended for most users"), or you can install using the package manager for your OS (nodejs.org).
 We highly recommend using a node version manager as these make it easier to install, upgrade, and switch between any particular version of node and npm.

### Windows

 There are a number of node version managers for Windows.
 Here we use nvm-windows, which is highly respected among node developers.

 Install the latest version using your installer of choice from the nvm-windows/releases page.
 After `nvm-windows` has installed, open a command prompt (or PowerShell) and enter the following command to download the most recent LTS version of nodejs and npm:

```bash
nvm install lts
```

 At time of writing the LTS version of nodejs is 18.15.0.
 You can set this as the *current version* to use with the command below:

```bash
nvm use 18.15.0
```

**Note:** If you get "Access Denied" warnings, you will need to run this command in a prompt with administration permissions.

Use the command `nvm --help` to find out other command line options, such as listing all available node versions, and all downloaded NVM versions.

### Ubuntu and macOS

 There are a number of node version managers for Ubuntu and macOS.
 nvm is one of the more popular, and is the original version on which `nvm-windows` is based.
 See nvm > Install & Update Script for the terminal instructions to install the latest version of nvm.

After `nvm` has installed, open a terminal enter the following command to download the most recent LTS version of nodejs and npm:

```bash
nvm install --lts
```

 At the time of writing, the LTS version of nodejs is 18.15.0.
 The command `nvm list` shows the downloaded set of version and the current version.
 You can set a particular version as the *current version* with the command below (the same as for `nvm-windows`)

```bash
nvm use 18.15.0
```

 Use the command `nvm --help` to find out other command line options.
 These are often similar to, or the same as, those offered by `nvm-windows`.

### Testing your Nodejs and npm installation

 Once you have set `nvm` to use a particular node version, you can test the installation.
 A good way to do this is to use the "version" command in your terminal/command prompt and check that the expected version string is returned:

```bash
> node -v
v18.15.0
```

The *Nodejs* package manager *npm* should also have been installed, and can be tested in the same way:

```bash
> npm -v
9.3.1
```

As a slightly more exciting test let's create a very basic "pure node" server that prints out "Hello World" in the browser when you visit the correct URL in your browser:

1. Copy the following text into a file named **hellonode.js**. This uses pure Node features (nothing from Express):

```js
//Load HTTP module
const http = require("http");
const hostname = "127.0.0.1";
const port = 3000;

//Create HTTP server and listen on port 3000 for requests
const server = http.createServer((req, res) => {
  //Set the response HTTP header with HTTP status and Content type
  res.statusCode = 200;
  res.setHeader("Content-Type", "text/plain");
  res.end("Hello World\n");
});

//listen for request on port 3000, and as a callback function have the port listened on logged
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
```

The code imports the "http" module and uses it to create a server (`createServer()`) that listens for HTTP requests on port 3000. The script then prints a message to the console about what browser URL you can use to test the server. The `createServer()` function takes as an argument a callback function that will be invoked when an HTTP request is received — this returns a response with an HTTP status code of 200 ("OK") and the plain text "Hello World".

**Note:** Don't worry if you don't understand exactly what this code is doing yet! We'll explain our code in greater detail once we start using Express!
2. Start the server by navigating into the same directory as your `hellonode.js` file in your command prompt, and calling `node` along with the script name, like so:

```bash
node hellonode.js
```

Once the server starts, you will see console output indicating the IP address the server is running on:
```

Server running at http://127.0.0.1:3000/
```

3. Navigate to the URL `http://127.0.0.1:3000`. If everything is working, the browser should display the string "Hello World".
Using npm
---------

 Next to *Node* itself, npm is the most important tool for working with *Node* applications.
 `npm` is used to fetch any packages (JavaScript libraries) that an application needs for development, testing, and/or production, and may also be used to run tests and tools used in the development process.

**Note:** From Node's perspective, *Express* is just another package that you need to install using npm and then require in your own code.

You can manually use npm to separately fetch each needed package. Typically we instead manage dependencies using a plain-text definition file named package.json. This file lists all the dependencies for a specific JavaScript "package", including the package's name, version, description, initial file to execute, production dependencies, development dependencies, versions of *Node* it can work with, etc. The **package.json** file should contain everything npm needs to fetch and run your application (if you were writing a reusable library you could use this definition to upload your package to the npm repository and make it available for other users).

### Adding dependencies

The following steps show how you can use npm to download a package, save it into the project dependencies, and then require it in a Node application.

**Note:** Here we show the instructions to fetch and install the *Express* package. Later on we'll show how this package, and others, are already specified for us using the *Express Application Generator*. This section is provided because it is useful to understand how npm works and what is being created by the application generator.

1. First create a directory for your new application and navigate into it:

```bash
mkdir myapp
cd myapp
```

2. Use the npm `init` command to create a **package.json** file for your application. This command prompts you for a number of things, including the name and version of your application and the name of the initial entry point file (by default this is **index.js**). For now, just accept the defaults:

```bash
npm init
```

If you display the **package.json** file (`cat package.json`), you will see the defaults that you accepted, ending with the license.

```json
{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
```

3. Now install Express in the `myapp` directory and save it in the dependencies list of your **package.json** file:

```bash
 npm install express
```

The dependencies section of your **package.json** will now appear at the end of the **package.json** file and will include *Express*.

```json
{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.17.1"
  }
}
```

4. To use the Express library you call the `require()` function in your **index.js** file to include it in your application.
 Create this file now, in the root of the "myapp" application directory, and give it the following contents:

```js
const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Example app listening on port ${port}!`);
});
```

This code shows a minimal "HelloWorld" Express web application.
 This imports the "express" module using `require()` and uses it to create a server (`app`) that listens for HTTP requests on port 3000 and prints a message to the console explaining what browser URL you can use to test the server.
 The `app.get()` function only responds to HTTP `GET` requests with the specified URL path ('/'), in this case by calling a function to send our *Hello World!* message.

**Note:** The backticks in the ``Example app listening on port ${port}!`` let us interpolate the value of `$port` into the string.
5. You can start the server by calling node with the script in your command prompt:

```bash
node index.js
```

You will see the following console output:
```

Example app listening on port 3000
```

6. Navigate to the URL `http://localhost:3000/`.
 If everything is working, the browser should display the string "Hello World!".
### Development dependencies

If a dependency is only used during development, you should instead save it as a "development dependency" (so that your package users don't have to install it in production). For example, to use the popular JavaScript Linting tool ESLint you would call npm as shown:

```bash
npm install eslint --save-dev
```

The following entry would then be added to your application's **package.json**:

```json
  "devDependencies": {
    "eslint": "^7.10.0"
  }
```

**Note:** "Linters" are tools that perform static analysis on software in order to recognize and report adherence/non-adherence to some set of coding best practice.

### Running tasks

In addition to defining and fetching dependencies you can also define *named* scripts in your **package.json** files and call npm to execute them with the run-script command. This approach is commonly used to automate running tests and parts of the development or build toolchain (e.g., running tools to minify JavaScript, shrink images, LINT/analyze your code, etc.).

**Note:** Task runners like Gulp and Grunt can also be used to run tests and other external tools.

For example, to define a script to run the *eslint* development dependency that we specified in the previous section we might add the following script block to our **package.json** file (assuming that our application source is in a folder /src/js):

```json
"scripts": {
  // …
  "lint": "eslint src/js"
  // …
}
```

To explain a little further, `eslint src/js` is a command that we could enter in our terminal/command line to run `eslint` on JavaScript files contained in the `src/js` directory inside our app directory. Including the above inside our app's package.json file provides a shortcut for this command — `lint`.

We would then be able to run *eslint* using npm by calling:

```bash
npm run-script lint
# OR (using the alias)
npm run lint
```

This example may not look any shorter than the original command, but you can include much bigger commands inside your npm scripts, including chains of multiple commands. You could identify a single npm script that runs all your tests at once.

Installing the Express Application Generator
--------------------------------------------

The Express Application Generator tool generates an Express application "skeleton". Install the generator using npm as shown:

```bash
npm install express-generator -g
```

**Note:** You may need to prefix this line with `sudo` on Ubuntu or macOS. The `-g` flag installs the tool globally so that you can call it from anywhere.

To create an *Express* app named "helloworld" with the default settings, navigate to where you want to create it and run the app as shown:

```bash
express helloworld
```

**Note:** Unless you're using an old nodejs version (< 8.2.0), you could alternatively skip the installation and run express-generator with npx.
 This has the same effect as installing and then running `express-generator` but does not install the package on your system:

```bash
npx express-generator helloworld
```

 You can also specify the template library to use and a number of other settings.
 Use the `help` command to see all the options:

```bash
express --help
```

 The generator will create the new Express app in a sub folder of your current location, displaying build progress on the console.
 On completion, the tool will display the commands you need to enter to install the Node dependencies and start the app.

 The new app will have a **package.json** file in its root directory.
 You can open this to see what dependencies are installed, including Express and the template library Jade:

```json
{
  "name": "helloworld",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "express": "~4.16.1",
    "http-errors": "~1.6.3",
    "jade": "~1.11.0",
    "morgan": "~1.9.1"
  }
}
```

Install all the dependencies for the helloworld app using npm as shown:

```bash
cd helloworld
npm install
```

Then run the app (the commands are slightly different for Windows and Linux/macOS), as shown below:

```bash
# Run helloworld on Windows with Command Prompt
SET DEBUG=helloworld:* & npm start

# Run helloworld on Windows with PowerShell
SET DEBUG=helloworld:* | npm start

# Run helloworld on Linux/macOS
DEBUG=helloworld:* npm start
```

The DEBUG command creates useful logging, resulting in an output like the following:

```bash
>SET DEBUG=helloworld:* & npm start

> helloworld@0.0.0 start D:\GitHub\expresstests\helloworld
> node ./bin/www

  helloworld:server Listening on port 3000 +0ms
```

Open a browser and navigate to `http://localhost:3000/` to see the default Express welcome page.

![Express - Generated App Default Screen](/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment/express_default_screen.png)

We'll talk more about the generated app when we get to the article on generating a skeleton application.

Summary
-------

You now have a Node development environment up and running on your computer that can be used for creating Express web applications. You've also seen how npm can be used to import Express into an application, and also how you can create applications using the Express Application Generator tool and then run them.

In the next article we start working through a tutorial to build a complete web application using this environment and associated tools.

See also
--------

* Downloads page (nodejs.org)
* Installing Node.js via package manager (nodejs.org)
* Installing Express (expressjs.com)
* Express Application Generator (expressjs.com)
* Using Node.js with Windows subsystem for Linux (docs.microsoft.com)
* Previous
* Overview: Express Nodejs
* Next