---
title: "Node.js and TypeScript Tutorial: Build a CRUD API"
description: "Learn how to use TypeScript to build a feature-complete Express API. Tutorial on how to use TypeScript with Express to create, read, update, and delete data."
authors:
  - name: "Dan Arias"
    url: "https://auth0.com/blog/authors/dan-arias/"
date: "Jan 14, 2021"
category: "Developers,Deep Dive,TypeScript"
tags: ["typescript", "nodejs", "node", "express", "auth0", "full-stack", "server", "backend", "api"]
url: "https://auth0.com/blog/node-js-and-typescript-tutorial-build-a-crud-api/"
---

# Node.js and TypeScript Tutorial: Build a CRUD API



This tutorial shows you how to **build a feature-complete API using Node.js, Express, and TypeScript** that lets clients perform data operations on resources that describe a restaurant menu. Using TypeScript with Node.js gives you access to optional static type-checking along with robust tooling for large apps and the latest ECMAScript features.

Learn also how to **define data models, create a data service, and quickly build modular endpoints**. As an option, you can also learn how to **secure the API using Auth0**.

<include src="whatabyte/BuildWhatYouBuild" tool="Express"/>

We tested this tutorial using Node.js `v14.15.1` and NPM `6.14.8`. If you need to install any of them, follow the [instructions provided by the Node.js Foundation for your operating system](https://nodejs.org/en/download/).

## Get Starts with TypeScript in Node.js

### Bootstrap a Node.js Project

Start by creating a project directory anywhere in your system and making it your current directory:

``` bash  
mkdir menu-api
cd menu-api
```

Next, initialize a Node.js project within the project directory by creating a `package.json` file with default settings:

``` bash  
npm init -y
```

### Install Project Dependencies

Your Node.js project requires a couple of dependencies to create a secure Express server with TypeScript. Install them like so:

``` bash  
npm i express dotenv cors helmet
```

Here's what each of the above packages does in your project:

- [`express`](https://www.npmjs.com/package/express): Fast, unopinionated, minimalist web framework for Node.js.

- [`dotenv`](https://www.npmjs.com/package/dotenv): Zero-dependency module that loads environment variables from a `.env` file into `process.env`.

- [`cors`](https://www.npmjs.com/package/cors): Express middleware to [enable CORS with various options](https://auth0.com/blog/cors-tutorial-a-guide-to-cross-origin-resource-sharing/).

- [`helmet`](https://www.npmjs.com/package/helmet): Express middleware to secure your apps by setting various HTTP headers, which mitigate common attack vectors.

To use TypeScript, you also need to install a stable version of [`typescript`](https://www.npmjs.com/package/typescript) as a developer dependency:

``` bash  
npm i -D typescript
```

To use TypeScript _effectively_, you need to install type definitions for the packages you installed previously:

``` bash  
npm i -D @types/node @types/express @types/dotenv @types/cors @types/helmet
```

When a package doesn't have built-in types, you can get its type definitions through the `@types` [npm namespace](https://docs.npmjs.com/about-scopes), which hosts TypeScript type definitions from the [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) project. Once you install the packages, the TypeScript compiler automatically includes the types, and your IDE can use them to provide you with code assistance.

<div class="alert alert-info alert-icon">
<i class="icon-budicon-500"></i>
<strong>
We tested this tutorial using Express <code>v4.17.1</code>, Node.js <code>v14.15.1</code>, and npm <code>6.14.8</code>.
</strong>
</div>

### Initialize TypeScript in Node.js

To help the TypeScript compiler understand your project's structure, you need to create a [`tsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) file within the directory you want to use as the root directory of the TypeScript project. In this case, your project directory and the TypeScript project directory are the same.

To easily generate the `tsconfig.json` file, ensure that you are under the project directory and issue the following command: 

``` bash  
npx tsc --init
```

That's all that you need for now to configure your TypeScript project with sensible defaults.

## Use Environmental Variables

Instead of using hard-coded configuration variables within files throughout your project, you can define all those variables in a central location and load them into the file modules that need them.  Developers working with Node.js commonly define this central location as a hidden file named `.env`, which you can create as follows:

``` bash  
touch .env
```

Populate the `.env` hidden file with the following variable that defines the port your server can use to listen for requests:

``` bash  
PORT=7000
```

As seen in the next section, any module of your project can load the variables defined within `.env` using the `dotenv` package.

> ⚠️ Caution: A `.env` file may contain sensitive information, such as API keys or secrets. Thus, add it to a project's `.gitignore` file to prevent it from being committed to version control.

## Create an Express App with TypeScript

To keep your application well-organized, create an `src` directory to host your Node.js application files:

``` bash  
mkdir src
```

Under this `src` directory, create a file named `index.ts` to serve as the entry point of the application:

``` bash  
touch src/index.ts
```

Add to `index.ts` the following template that outlines an Express server: 

``` typescript  
/**
 * Required External Modules
 */

/**
 * App Variables
 */

/**
 *  App Configuration
 */

/**
 * Server Activation
 */
```

Next, under the `Required External Modules` section, import the project dependencies you installed earlier and load any environmental variables from the local `.env` file using the `dotenv.config()` method:

``` typescript  
/**
 * Required External Modules
 */

import * as dotenv from "dotenv";
import express from "express";
import cors from "cors";
import helmet from "helmet";

dotenv.config();
```

Under the `App Variables` section, check if Node.js loaded the environmental variable `PORT` into `process.env`. If so, parse its value as a `number` type and create an instance of an Express application; otherwise, exit the application:

``` typescript  
/**
 * App Variables
 */

if (!process.env.PORT) {
   process.exit(1);
}

const PORT: number = parseInt(process.env.PORT as string, 10);

const app = express();
```

Under the `App Configuration` section, mount the middleware functions from the packages that you are importing into this entry point module:

``` typescript  
/**
 *  App Configuration
 */

app.use(helmet());
app.use(cors());
app.use(express.json());
```

[`helmet`](https://helmetjs.github.io/) is a collection of 14 small middleware functions that set HTTP response headers. Mounting `helmet()` doesn't include all of these middleware functions but provides you with [sensible defaults](https://www.npmjs.com/package/helmet#how-it-works) such as [DNS Prefetch Control](https://helmetjs.github.io/docs/dns-prefetch-control/), [Frameguard](https://helmetjs.github.io/docs/frameguard/), [Hide Powered-By](https://helmetjs.github.io/docs/hide-powered-by/), [HSTS](https://helmetjs.github.io/docs/hsts/), [IE No Open](https://helmetjs.github.io/docs/ienoopen/), [Don't Sniff Mimetype](https://helmetjs.github.io/docs/dont-sniff-mimetype/), and [XSS Filter](https://helmetjs.github.io/docs/xss-filter/).

By mounting `cors()`, you enable all CORS requests. With `express.json()`, you parse incoming requests with JSON payloads, which populates the `request` object with a new `body` object containing the parsed data.

Finally, under the `Server Activation` section, you create an Express server:

``` typescript  
/**
 * Server Activation
 */

app.listen(PORT, () => {
  console.log(`Listening on port ${PORT}`);
});
```

## Improve TypeScript Development Workflow

The TypeScript compilation process can increase the bootstrapping time of an application. However, you don't need to recompile the entire project whenever there's a change in its source code. You can set up [`ts-node-dev`](https://github.com/whitecolor/ts-node-dev) to significantly decrease the time it takes to restart your application when you make a change.

Start by installing this package to power up your development workflow:

``` bash  
npm i -D ts-node-dev
```

`ts-node-dev` restarts a target Node.js process when any of the required files change. However, it shares the Typescript compilation process between restarts, which can significantly increase the restart speed.

You can create a `dev` npm script in `package.json` to run your server:

``` json  
{
  "name": "menu-api",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "ts-node-dev --respawn --pretty --transpile-only src/index.ts"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": { ... },
  "devDependencies": { ... }
}
```

Let's briefly break down the options that `ts-node-dev` takes:

- `--respawn`: Keep watching for changes after the script has exited.

- `--pretty`: Use pretty diagnostic formatter (`TS_NODE_PRETTY`).

- `--transpile-only`: Use TypeScript's faster `transpileModule` (`TS_NODE_TRANSPILE_ONLY`).

- `src/index.ts`: This is the application's entry file.

Since `ts-node-dev` is a tweaked version of [`node-dev`](https://github.com/fgnass/node-dev) that uses [`ts-node`](https://github.com/TypeStrong/ts-node) under the hood, some of its options are the combined options of those two packages. Refer to its ["Usage" document](https://github.com/whitecolor/ts-node-dev#usage) for more details and available options.

Now, simply run the `dev` script to launch your project:

``` bash  
npm run dev
```

If everything is working correctly, you'll see a message indicating that the server is listening for requests on port `7000`.

You are ready to develop this application further using TypeScript interfaces to define data models, services to manipulate the API resources, and much more.

## Model Data with TypeScript Interfaces

<include src="whatabyte/BuildMenuItemModel" />

Since you are using TypeScript to build your API, you have different options to define and enforce the structure of objects during development. You can use either classes or interfaces to define custom types. You can use interfaces for the menu items as they are not part of the compiled JavaScript bundle, keeping it smaller, and your application won't need instances of a menu item.

To keep your project organized, create an `items` directory under the `src` directory to store all files related to menu items:

``` bash  
mkdir src/items
```

To start modeling your data, create a file to hold the definition of a `BaseItem` and an `Item` type:

``` bash  
touch src/items/item.interface.ts
```

Populate `src/items/item.interface.ts` with the following definition:

``` typescript  
// src/items/item.interface.ts

export interface BaseItem {
  name: string;
  price: number;
  description: string;
  image: string;
}

export interface Item extends BaseItem {
  id: number;
}
```

There will be scenarios where you only need to assert the item's structure without its `id`, such as when you get a payload to create a new item or update an existing one. In those types of requests, `POST` and `PUT`, the client sends the item `id` as a query parameter. For those cases, you'll use the `BaseItem` interface.  

Next, create a file to hold the definition of an `Items` type, a bundle of elements of type `Item`:

``` bash  
touch src/items/items.interface.ts
```

Populate `src/items/items.interface.ts` as follows:

``` typescript  
// src/items/items.interface.ts

import { Item } from "./item.interface";

export interface Items {
  [key: number]: Item;
}
```

## Create a Node.js Service with TypeScript

A service lets you encapsulate related business logic that you can share across multiple projects. As such, your application can use a service to access and manipulate records from your store.

Create a file to define a service module:

``` bash  
touch src/items/items.service.ts
```

Populate the `src/items/items.service.ts` file with the following template:

``` typescript  
// src/items/items.service.ts

/**
 * Data Model Interfaces
 */


/**
 * In-Memory Store
 */


/**
 * Service Methods
 */
```

Now, under the `Data Model Interfaces` section, import the interfaces you created earlier:

``` typescript  
/**
 * Data Model Interfaces
 */

import { BaseItem, Item } from "./item.interface";
import { Items } from "./items.interface";
```

To keep this tutorial simpler, you are not using an external database to store records. Instead, under the `In-Memory Store` section, you create a simple in-memory store represented as an object:

``` typescript  
/**
 * In-Memory Store
 */

let items: Items = {
  1: {
    id: 1,
    name: "Burger",
    price: 599,
    description: "Tasty",
    image: "https://cdn.auth0.com/blog/whatabyte/burger-sm.png"
  },
  2: {
    id: 2,
    name: "Pizza",
    price: 299,
    description: "Cheesy",
    image: "https://cdn.auth0.com/blog/whatabyte/pizza-sm.png"
  },
  3: {
    id: 3,
    name: "Tea",
    price: 199,
    description: "Informative",
    image: "https://cdn.auth0.com/blog/whatabyte/tea-sm.png"
  }
};
```

It's important to note that anytime that you restart the server, Express wipes the in-memory store. However, since you are using `ts-node-dev`, that only happens when you make changes to the service module file.

Next, create methods to perform read and write operations on the `items` store. Start by creating two methods under the `Service Methods` section to find store elements:

``` typescript  
/**
 * Service Methods
 */

export const findAll = async (): Promise<Item[]> => Object.values(items);

export const find = async (id: number): Promise<Item> => items[id];
```

To simulate the asynchronous nature of read and write operations, all the service methods are `async` methods. `findAll` returns the whole `items` store object, while `find` receives an `id` parameter that it uses to look up and return a single store element if found.

Next, define a method to create a new item in the store:

``` typescript  
/**
 * Service Methods
 */

export const findAll = async (): Promise<Items> => {...};

export const find = async (id: number): Promise<Item> => {...};

export const create = async (newItem: BaseItem): Promise<Item> => {
  const id = new Date().valueOf();

  items[id] = {
    id,
    ...newItem,
  };

  return items[id];
};
```

The `create` method is simple: it receives an object of type `BaseItem` as an argument, providing all the required values to define a new item in the store, except the item's `id`. To create a unique `id` value for each new element added to the store, you use the value of the current `Date`, based on the number of milliseconds between `1 January 1970 00:00:00 UTC` and the current time.


Right below, add a method to update an existing store item:

``` typescript  
/**
 * Service Methods
 */

export const findAll = async (): Promise<Item[]> => {...};

export const find = async (id: number): Promise<Item> => {...};

export const create = async (newItem: BaseItem): Promise<Item> => {...};

export const update = async (
  id: number,
  itemUpdate: BaseItem
): Promise<Item | null> => {
  const item = await find(id);

  if (!item) {
    return null;
  }

  items[id] = { id, ...itemUpdate };

  return items[id];
};
```

The `update` method receives the item `id` property and an `itemUpdate` object as arguments. You use the `id` to find the item in the store to update it wit the properties of `itemUpdate`. If the store doesn't have the item, you return `null`.

Finally, define a method to remove an item from the store:

``` typescript  
/**
 * Service Methods
 */

export const findAll = async (): Promise<Item[]> => {...};

export const find = async (id: number): Promise<Item> => {...};

export const create = async (newItem: BaseItem): Promise<Item> => {...};

export const update = async (
  id: number,
  itemUpdate: BaseItem
): Promise<Item | null> => {...};

export const remove = async (id: number): Promise<null | void> => {
  const item = await find(id);

  if (!item) {
    return null;
  }

  delete items[id];
};
```

The `remove` method receives an `id` value as a parameter and uses it to look up an item in the store and to delete it if found.

You've now completed the creation of a nimble service module using TypeScript and Node.js. Any other project can use the code of this service module as it's not tied to any particular framework. You use it in the next section to create your API controllers.

It's worth mentioning that you could have used a TypeScript class to define and encapsulate the service logic; however, using functions makes testing your service module much easier. 

## Create Express Controllers

For this application, you'll create endpoints to access an `items` resource to perform read and write operations on menu items:

``` bash  
# get all items
GET /api/menu/items

# get a single item using an id parameter
GET /api/menu/items/:id

# create an item
POST /api/menu/items

# update an item using an id parameter
PUT /api/menu/items/:id

# remove an item using an id parameter
DELETE /api/menu/items/:id
```

> You can refer to the [WHATABYTE Menu API](https://github.com/auth0-blog/wab-docs) document to get more details on the signature, input, and response of each endpoint.

Only the `GET` endpoints are public, so let's start with those.

Instead of defining the application routes inside the entry-point file, `index.ts`, you can create an Express router as a separate module with all your route handling details and import it wherever it's needed.

To start, under the `/src/items` directory, create an `items.router.ts` file: 

``` bash  
touch src/items/items.router.ts
```

When a client application makes a request to your server, Express forwards the request to functions designed to handle that type of request (`GET` or `POST`) on the specified resource (`items/`). As such, each of these functions defines a route handler, which is also commonly referred to as a _controller_.

Populate `src/items/items.router.ts` with the following template that outlines the architecture of the router:

``` typescript  
/**
 * Required External Modules and Interfaces
 */

/**
 * Router Definition
 */

/**
 * Controller Definitions
 */

// GET items

// GET items/:id

// POST items

// PUT items/:id

// DELETE items/:id

```

With the template in place, add the following under the `Required External Modules and Interfaces` section:

``` typescript  
/**
 * Required External Modules and Interfaces
 */

import express, { Request, Response } from "express";
import * as ItemService from "./items.service";
import { BaseItem, Item } from "./item.interface";
```

Here, you are importing the `express` package and two of its internal type definitions, `Request` and `Response`, which you can use to type the callback functions of your Express controllers.

You also import all the exported functions from the `items.service` module and bundle them locally as an `ItemService` object, making it easier for you to avoid name collisions and to pinpoint from what package a function comes.

Finally, you also import the `Item` and `Items` interfaces, which are necessary to type the return values from the `ItemService` functions.

Next, define an Express router under the `Router Definition` section:

``` typescript  
/**
 * Router Definition
 */

export const itemsRouter = express.Router();
```

Here, you use the [`express.Router` class](https://expressjs.com/en/guide/routing.html#express-router) to create a modular and mountable bundle of route handlers. An Express router instance is often referred to as a "mini-app" because it functions as a complete middleware and routing system, which is essential for organizing the architecture of your Node.js project into components that you can easily test and re-use.

You export the `itemsRouter` right away, even though you have not defined its routing properties yet. Any property that you define later in the module on the `itemsRouter` object would be accessible by any module that imports it.

Define each controller function by adding the following under the `Controller Definitions` section:

``` typescript  
/**
 * Controller Definitions
 */

// GET items

itemsRouter.get("/", async (req: Request, res: Response) => {
  try {
    const items: Item[] = await ItemService.findAll();

    res.status(200).send(items);
  } catch (e) {
    res.status(500).send(e.message);
  }
});

// GET items/:id

itemsRouter.get("/:id", async (req: Request, res: Response) => {
  const id: number = parseInt(req.params.id, 10);

  try {
    const item: Item = await ItemService.find(id);

    if (item) {
      return res.status(200).send(item);
    }

    res.status(404).send("item not found");
  } catch (e) {
    res.status(500).send(e.message);
  }
});

// POST items

itemsRouter.post("/", async (req: Request, res: Response) => {
  try {
    const item: BaseItem = req.body;

    const newItem = await ItemService.create(item);

    res.status(201).json(newItem);
  } catch (e) {
    res.status(500).send(e.message);
  }
});

// PUT items/:id

itemsRouter.put("/:id", async (req: Request, res: Response) => {
  const id: number = parseInt(req.params.id, 10);

  try {
    const itemUpdate: Item = req.body;

    const existingItem: Item = await ItemService.find(id);

    if (existingItem) {
      const updatedItem = await ItemService.update(id, itemUpdate);
      return res.status(200).json(updatedItem);
    }

    const newItem = await ItemService.create(itemUpdate);

    res.status(201).json(newItem);
  } catch (e) {
    res.status(500).send(e.message);
  }
});

// DELETE items/:id

itemsRouter.delete("/:id", async (req: Request, res: Response) => {
  try {
    const id: number = parseInt(req.params.id, 10);
    await ItemService.remove(id);

    res.sendStatus(204);
  } catch (e) {
    res.status(500).send(e.message);
  }
});
```

The logic of the controllers is compact as they delegate the bulk of their operations to the functions of the `ItemService` module. If you ever need to use a database like MongoDB or PostgreSQL to persist data, you only need to modify the logic of the service provider, the `ItemService` module, and not the logic of the consumers, your controllers.

To complete the setup of your controllers, you need to wire the `itemsRouter` with your Express app. To do so, open `index.ts` and import the router under the `Required External Modules` section:

``` typescript  
/**
 * Required External Modules
 */

import * as dotenv from "dotenv";
import express from "express";
import cors from "cors";
import helmet from "helmet";
import { itemsRouter } from "./items/items.router";

dotenv.config();
```
 
Next, within this file, update the `App Configuration` section as follows to make use of the router:

``` typescript  
/**
 *  App Configuration
 */

app.use(helmet());
app.use(cors());
app.use(express.json());
app.use("/api/menu/items", itemsRouter);
```

The [`app.use()`](https://expressjs.com/en/5x/api.html#app.use) method can take as an argument an optional `path` and a `callback` function that represents one or more middleware functions. In this case, you tell your Express app to invoke the `itemsRouter` middleware functions whenever the `api/menu/items` route path is requested.

<include src="whatabyte/BuildTestEndpoints" tool="Express"/>

## Implement Express Error Handling

In Express, the order in which you declare and invoke middleware is essential for the architecture of your application. What should happen when a client makes a server request that doesn't match any server routes? The ideal behavior is to respond to the client with a [`400 Bad Request`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/400) status code.

A good way to handle this is to create an `HttpException` class that helps you encapsulate errors related to HTTP requests and a middleware function to help you manage and issue the error response.

To continue having an organized application architecture, create a `common` directory under the `src` directory to host any classes or interfaces that you use across different project modules:

``` bash  
mkdir src/common
```

Within the `src/common` directory, create a file to define the `HttpException` class:

``` bash  
touch src/common/http-exception.ts
```

Populate `src/common/http-exception.ts` as follows:

``` typescript  
// src/common/http-exception.ts

export default class HttpException extends Error {
  statusCode?: number;
  status?: number;
  message: string;
  error: string | null;

  constructor(statusCode: number, message: string, error?: string) {
    super(message);

    this.statusCode = statusCode;
    this.message = message;
    this.error = error || null;
  }
}
```

With this helper class in place, proceed to create a `middleware` directory under the `src` directory to host all the files that define custom middleware functions:

``` bash  
mkdir src/middleware
```

To start, define a middleware function that handles request errors in an `error.middleware.ts` file inside `src/middleware` as follows:

``` bash  
touch src/middleware/error.middleware.ts
```

Now, populate `src/middleware/error.middleware.ts` with this:

``` typescript  
// src/middleware/error.middleware.ts

import HttpException from "../common/http-exception";
import { Request, Response, NextFunction } from "express";

export const errorHandler = (
  error: HttpException,
  request: Request,
  response: Response,
  next: NextFunction
) => {
  const status = error.statusCode || error.status || 500;

  response.status(status).send(error);
};
```

Here, you receive an error of type `HttpException` and return an appropriate error based on its properties. If `error.status` and `error.message` are defined, you include those in the server response. Otherwise, you default to a generic `500 Internal Server Error` status code and a generic message.

It's important to note that you must provide four arguments to [identify a function as an error-handling middleware function in Express](https://expressjs.com/en/guide/using-middleware.html#middleware.error-handling). You must specify the `next` object to maintain the error-handling signature even if you don't use it. Otherwise, Express interprets the `next` object as a regular middleware function, and it won't handle any errors.

Now, also consider that the condition of [a route not existing is not considered an error by Express](https://github.com/expressjs/express/issues/2718#issuecomment-126794574) when you use the framework to build a RESTful API. The REST architecture model uses HTTP status codes to respond to the client. A missing resource should not be an error but a condition you need to report to the client.

As such, Express won't call your `errorHandler` middleware function if you request the `employees` resource, for example:

``` bash  
curl http://localhost:7000/employees/ -i
```

Executing the request above returns the following generic HTML response:

``` html  

HTTP/1.1 404 Not Found
X-DNS-Prefetch-Control: off
X-Frame-Options: SAMEORIGIN
Strict-Transport-Security: max-age=15552000; includeSubDomains
X-Download-Options: noopen
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Access-Control-Allow-Origin: *
Content-Security-Policy: default-src 'none'
Content-Type: text/html; charset=utf-8
Content-Length: 149
Date: Thu, 30 Jan 2020 14:51:01 GMT
Connection: keep-alive
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Error</title>
</head>
<body>
<pre>Cannot GET /employees/</pre>
</body>
</html>

```

To customize how your app responds to undefined resources, create an additional middleware function to catch `404` conditions. Inside the `src/middleware` directory, create a `not-found.middleware.ts` file as follows:

``` bash  
touch src/middleware/not-found.middleware.ts
```

Then, add the following code to `src/middleware/not-found.middleware.ts`:

``` typescript  
// src/middleware/not-found.middleware.ts

import { Request, Response, NextFunction } from "express";

export const notFoundHandler = (
  request: Request,
  response: Response,
  next: NextFunction
) => {

  const message = "Resource not found";

  response.status(404).send(message);
};
```

You now need to wire these middleware functions with your Express app. Open `src/index.ts` and update its `Required External Modules` section to import these error-handling middleware functions:

``` typescript  
/**
 * Required External Modules
 */

import * as dotenv from "dotenv";
import express from "express";
import cors from "cors";
import helmet from "helmet";
import { itemsRouter } from "./items/items.router";
import { errorHandler } from "./middleware/error.middleware";
import { notFoundHandler } from "./middleware/not-found.middleware";

dotenv.config();
```

Next, update the `App Configuration` section to mount the `errorHandler` and `notFoundHandler` functions:

``` typescript  
/**
 *  App Configuration
 */

app.use(helmet());
app.use(cors());
app.use(express.json());
app.use("/api/menu/items", itemsRouter);

app.use(errorHandler);
app.use(notFoundHandler);
```

Your application can't reach any routes you define after mounting the `errorHandler` middleware function because you close the request-response cycle within `errorHandler` by sending a response to the client. As such, you must mount the `errorHandler` middleware function after you have mounted all the controller functions of your application.

But, as noted earlier, `errorHandler` won't catch `404` errors. However, you can catch these errors by making `notFoundHandler` the last middleware function that you mount, which effectively creates a _catch-all_ handler for your app.

Make the following request and observe that you now get your custom `404` response, `Resource not found`, instead of the generic HTML one:

``` bash  
curl http://localhost:7000/employees/ -i
```

<include src="whatabyte/BuildUseDemoClient" />

<include src="whatabyte/BuildSecurityConsiderations" />

<include src="tutorial/NextButton" nextPart="node-js-and-typescript-tutorial-secure-an-express-api/" completedMessage="Next Step: I'm Ready to Secure My Express API"/>

<include src="tutorial/IssueButton" communityTopic="node-js-and-typescript-tutorial-build-a-crud-api/56206/"/>
