Ошибка 404 express

How should I structure my application?

There is no definitive answer to this question. The answer depends
on the scale of your application and the team that is involved. To be as
flexible as possible, Express makes no assumptions in terms of structure.

Routes and other application-specific logic can live in as many files
as you wish, in any directory structure you prefer. View the following
examples for inspiration:

  • Route listings
  • Route map
  • MVC style controllers

Also, there are third-party extensions for Express, which simplify some of these patterns:

  • Resourceful routing

How do I define models?

Express has no notion of a database. This concept is
left up to third-party Node modules, allowing you to
interface with nearly any database.

See LoopBack for an Express-based framework that is centered around models.

How can I authenticate users?

Authentication is another opinionated area that Express does not
venture into. You may use any authentication scheme you wish.
For a simple username / password scheme, see this example.

Which template engines does Express support?

Express supports any template engine that conforms with the (path, locals, callback) signature.
To normalize template engine interfaces and caching, see the
consolidate.js
project for support. Unlisted template engines might still support the Express signature.

For more information, see Using template engines with Express.

How do I handle 404 responses?

In Express, 404 responses are not the result of an error, so
the error-handler middleware will not capture them. This behavior is
because a 404 response simply indicates the absence of additional work to do;
in other words, Express has executed all middleware functions and routes,
and found that none of them responded. All you need to
do is add a middleware function at the very bottom of the stack (below all other functions)
to handle a 404 response:

app.use((req, res, next) => {
  res.status(404).send("Sorry can't find that!")
})

Add routes dynamically at runtime on an instance of express.Router()
so the routes are not superseded by a middleware function.

How do I setup an error handler?

You define error-handling middleware in the same way as other middleware,
except with four arguments instead of three; specifically with the signature (err, req, res, next):

app.use((err, req, res, next) => {
  console.error(err.stack)
  res.status(500).send('Something broke!')
})

For more information, see Error handling.

How do I render plain HTML?

You don’t! There’s no need to “render” HTML with the res.render() function.
If you have a specific file, use the res.sendFile() function.
If you are serving many assets from a directory, use the express.static()
middleware function.

Previous: More examples

Время на прочтение
7 мин

Количество просмотров 24K

Когда я только начинал работать с Express и пытался разобраться с тем, как обрабатывать ошибки, мне пришлось нелегко. Возникало такое ощущение, будто никто не писал о том, что мне было нужно. В итоге мне пришлось самому искать ответы на мои вопросы. Сегодня я хочу рассказать всё, что знаю об обработке ошибок в Express-приложениях. Начнём с синхронных ошибок.

Обработка синхронных ошибок

Если вам нужно обработать синхронную ошибку, то вы можете, для начала, с помощью инструкции throw, выдать такую ошибку в обработчике запроса Express. Обратите внимание на то, что обработчики запросов ещё называют «контроллерами», но я предпочитаю использовать термин «обработчик запросов» так как он кажется мне понятнее.

Вот как это выглядит:

app.post('/testing', (req, res) => {
  throw new Error('Something broke! ')
})

Такие ошибки можно перехватить с помощью обработчика ошибок Express. Если вы не написали собственный обработчик ошибок (подробнее об этом мы поговорим ниже), то Express обработает ошибку с помощью обработчика, используемого по умолчанию.

Вот что делает стандартный обработчик ошибок Express:

  1. Устанавливает код состояния HTTP-ответа в значение 500.
  2. Отправляет сущности, выполнившей запрос, текстовый ответ.
  3. Логирует текстовый ответ в консоль.

Сообщение об ошибке, выведенное в консоль

Обработка асинхронных ошибок

Для обработки асинхронных ошибок нужно отправить ошибку обработчику ошибок Express через аргумент next:

app.post('/testing', async (req, res, next) => {
  return next(new Error('Something broke again! '))
})

Вот что попадёт в консоль при логировании этой ошибки.

Сообщение об ошибке, выведенное в консоль

Если вы пользуетесь в Express-приложении конструкцией async/await, то вам понадобится использовать функцию-обёртку, наподобие express-async-handler. Это позволяет писать асинхронный код без блоков try/catch. Подробнее об async/await в Express можно почитать здесь.

const asyncHandler = require('express-async-handler')

app.post('/testing', asyncHandler(async (req, res, next) => {
  // Сделать что-нибудь
}))

После того, как обработчик запроса обёрнут в express-async-handler, то можно, так же, как было описано выше, выбросить ошибку с использованием инструкции throw. Эта ошибка попадёт к обработчику ошибок Express.

app.post('/testing', asyncHandler(async (req, res, next) => {
  throw new Error('Something broke yet again! ')
}))

Сообщение об ошибке, выведенное в консоль

Написание собственного обработчика ошибок

Обработчики ошибок Express принимают 4 аргумента:

  1. error
  2. req
  3. res
  4. next

Размещать их нужно после промежуточных обработчиков и маршрутов.

app.use(/*...*/)
app.get(/*...*/)
app.post(/*...*/)
app.put(/*...*/)
app.delete(/*...*/)

// Собственный обработчик ошибок нужно поместить после всех остальных промежуточных обработчиков
app.use((error, req, res, next) => { /* ... */ })

Если создать собственный обработчик ошибок, то Express прекратит использование стандартного обработчика. Для того чтобы обработать ошибку, нужно сформировать ответ для фронтенд-приложения, которое обратилось к конечной точке, в которой возникла ошибка. Это означает, что нужно выполнить следующие действия:

  1. Сформировать и отправить подходящий код состояния ответа.
  2. Сформировать и отправить подходящий ответ.

То, какой именно код состояния подойдёт в каждом конкретном случае, зависит от того, что именно произошло. Вот список типичных ошибок, к обработке которых вы должны быть готовы:

  1. Ошибка 400 Bad Request. Используется в двух ситуациях. Во-первых — тогда, когда пользователь не включил в запрос необходимое поле (например — в отправленной платёжной форме не заполнено поле со сведениями о кредитной карте). Во-вторых — тогда, когда в запросе содержатся некорректные данные (например — ввод в поле пароля и в поле подтверждения пароля разных паролей).
  2. Ошибка 401 Unauthorized. Этот код состояния ответа применяется в том случае, если пользователь ввёл неправильные учётные данные (вроде имени пользователя, адреса электронной почты или пароля).
  3. Ошибка 403 Forbidden. Используется в тех случаях, когда пользователю не разрешён доступ к конечной точке.
  4. Ошибка 404 Not Found. Применяется в тех случаях, когда конечную точку невозможно обнаружить.
  5. Ошибка 500 Internal Server Error. Применяется тогда, когда запрос, отправленный фронтендом, сформирован правильно, но на бэкенде при этом возникла какая-то ошибка.

После того, как определён подходящий код состояния ответа, его нужно установить с помощью res.status:

app.use((error, req, res, next) => {
  // Ошибка, выдаваемая в ответ на неправильно сформированный запрос
  res.status(400)
  res.json(/* ... */)
})

Код состояния ответа должен соответствовать сообщению об ошибке. Для этого нужно отправлять код состояния вместе с ошибкой.

Легче всего это сделать с помощью пакета http-errors. Он позволяет отправлять в ошибке три фрагмента информации:

  1. Код состояния ответа.
  2. Сообщение, сопутствующее ошибке.
  3. Любые данные, которые нужно отправить (это необязательно).

Вот как установить пакет http-errors:

npm install http-errors --save

Вот как этим пакетом пользоваться:

const createError = require('http-errors')

// Создание ошибки
throw createError(status, message, properties)

Рассмотрим пример, который позволит как следует в этом всём разобраться.

Представим, что мы пытаемся обнаружить пользователя по адресу его электронной почты. Но этого пользователя найти не удаётся. В результате мы решаем отправить в ответ на соответствующий запрос ошибку User not found, сообщающую вызывающей стороне о том, что пользователь не найден.

Вот что нам нужно будет сделать при создании ошибки:

  1. Установить код состояния ответа как 400 Bad Request (ведь пользователь ввёл неправильные данные). Это будет наш первый параметр.
  2. Отправить вызывающей стороне сообщение наподобие User not found. Это будет второй параметр.

app.put('/testing', asyncHandler(async (req, res) => {
  const { email } = req.body
  const user = await User.findOne({ email })

  // Если пользователь не найден - выбросим ошибку
  if (!user) throw createError(400, `User '${email}' not found`)
}))

Получить код состояния можно с помощью конструкции error.status, а сообщение ошибки — с помощью error.message:

// Логирование ошибки
app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})

Результат логирования ошибки в консоли

Затем состояние ответа устанавливают с помощью res.status, а сообщение записывают в res.json:

app.use((error, req, res, next) => {
  // Установка кода состояния ответа
  res.status(error.status)

  // Отправка ответа
  res.json({ message: error.message })
})

Лично я предпочитаю отправлять в подобных ответах код состояния, сообщение и результат трассировки стека. Это облегчает отладку.

app.use((error, req, res, next) => {
  // Установка кода состояния ответа
  res.status(error.status)

  // Отправка ответа
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

▍Код состояния ответа, используемый по умолчанию

Если источником ошибки не является createError, то у неё не будет свойства status. Вот пример, в котором сделана попытка прочесть несуществующий файл с помощью fs.readFile:

const fs = require('fs')
const util = require('util')

// Преобразуем readFile из функции, использующей коллбэки, в async/await-функцию.
// Подробности об этом смотрите здесь: https://zellwk.com/blog/callbacks-to-promises
const readFilePromise = util.promisify(fs.readFile)

app.get('/testing', asyncHandler(async (req, res, next) => {
  const data = await readFilePromise('some-file')
})

У такого объекта ошибки не будет свойства status:

app.use((error, req, res, next) => {
  console.log('Error status: ', error.status)
  console.log('Message: ', error.message)
})

Результат логирования ошибки в консоли

В подобных случаях можно задать код ошибки, используемый по умолчанию. А именно, речь идёт об ошибке 500 Internal Server Error:

app.use((error, req, res, next) => {
  res.status(error.status || 500)
  res.json({
    status: error.status,
    message: error.message,
    stack: error.stack
  })
})

▍Изменение кода состояния ошибки

Предположим, мы собираемся прочитать некий файл, воспользовавшись данными, предоставленными пользователем. Если такого файла не существует, это значит, что нам нужно выдать ошибку 400 Bad Request. Ведь в том, что файл найти не удаётся, нет вины сервера.

В подобном случае нужно воспользоваться конструкцией try/catch для перехвата исходной ошибки. Затем нужно воссоздать объект ошибки с помощью createError:

app.get('/testing', asyncHandler(async (req, res, next) => {
  try {
    const { file } = req.body
    const contents = await readFilePromise(path.join(__dirname, file))
  } catch (error) {
    throw createError(400, `File ${file} does not exist`)
  }
})

▍Обработка ошибок 404

Если запрос прошёл через все промежуточные обработчики и маршруты, но так и не был обработан, это означает, что конечная точка, соответствующая такому запросу, не была найдена.

Для обработки ошибок 404 Not Found нужно добавить, между маршрутами и обработчиком ошибок, дополнительный обработчик. Вот как выглядит создание объекта ошибки 404:

// Промежуточные обработчики...
// Маршруты...

app.use((req, res, next) => {
  next(createError(404))
})

// Обработчик ошибок...

Сведения об ошибке

▍Замечания об ошибке ERR_HTTP_HEADERS_SENT

Не впадайте в панику если видите сообщение об ошибке ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client. Она возникает из-за того, что в одном и том же обработчике многократно вызывается метод, устанавливающий заголовки ответа. Вот методы, вызов которых приводит к автоматической установке заголовков ответа:

  1. res.send
  2. res.json
  3. res.render
  4. res.sendFile
  5. res.sendStatus
  6. res.end
  7. res.redirect

Так, например, если вы вызовете методы res.render и res.json в одном и том же обработчике ответа, то вы получите ошибку ERR_HTTP_HEADERS_SENT:

app.get('/testing', (req, res) => {
  res.render('new-page')
  res.json({ message: '¯\_(ツ)_/¯' })
})

В результате, в том случае, если вы сталкиваетесь с этой ошибкой, тщательно проверьте код обработчиков ответа и убедитесь в том, что в нём нет ситуаций, в которых вызывается несколько вышеописанных методов.

▍Обработка ошибок и потоковая передача данных

Если что-то идёт не так при потоковой передаче ответа фронтенду, то можно столкнуться с той же самой ошибкой ERR_HTTP_HEADERS_SENT.

В подобном случае обработку ошибок нужно передать стандартным обработчикам. Такой обработчик отправит ошибку и автоматически закроет соединение.

app.use((error, req, res, next) => {
  // Сделать это нужно только в том случае, если ответ передаётся в потоковом режиме
  if (res.headersSent) {
    return next(error)
  }

  // Остальной код обработки ошибок
})

Итоги

Сегодня я рассказал вам всё, что знаю об обработке ошибок в Express. Надеюсь, это поможет вам писать более надёжные Express-приложения.

Уважаемые читатели! Как вы обрабатываете ошибки в своих Node.js-проектах?

The easiest way to do it is to have a catch all for Error Page

// Step 1: calling express
const express = require("express");
const app = express();

Then

// require Path to get file locations
const path = require("path");

Now you can store all your «html» pages (including an error «html» page) in a variable

// Storing file locations in a variable
var indexPg = path.join(__dirname, "./htmlPages/index.html");
var aboutPg = path.join(__dirname, "./htmlPages/about.html");
var contactPg = path.join(__dirname, "./htmlPages/contact.html");
var errorPg = path.join(__dirname, "./htmlPages/404.html"); //this is your error page

Now you simply call the pages using the Get Method and have a catch all for any routes not available to direct to your error page using app.get(«*»)

//Step 2: Defining Routes
//default page will be your index.html
app.get("/", function(req,res){
  res.sendFile(indexPg);
});
//about page
app.get("/about", function(req,res){
  res.sendFile(aboutPg);
});
//contact page
app.get("/contact", function(req,res){
  res.sendFile(contactPg);
});
//catch all endpoint will be Error Page
app.get("*", function(req,res){
  res.sendFile(errorPg);
});

Don’t forget to set up a Port and Listen for server:

// Setting port to listen on
const port = process.env.PORT || 8000;
// Listening on port
app.listen(port, function(){
  console.log(`http://localhost:${port}`);
})

This should now show your error page for all unrecognized endpoints!

Express.js is a powerful framework for node.js. One of the main advantages of this framework is defining different routes or middleware to handle the client’s different incoming requests. In this article, we will discuss how to add a 404 error page i.e not found using the express server. 404 is the status code which means not found in the server.

Installing module: Install the required module using the following command.

npm install express

Project structure: It will look like this.

index.js

const express = require("express")

const app = express()

app.get("/hello", (req, res, next) => {

    res.send("This is the hello response");

})

app.use((req, res, next) => {

    res.status(404).send(

        "<h1>Page not found on the server</h1>")

})

app.listen(3000, () => {

    console.log("Server is Running")

})

Run the index.js file using the below command:

node index.js

Output: Now open your browser and go to http://localhost:3000/, the server will respond no page found.

Last Updated :
28 Jun, 2021

Like Article

Save Article

Building a web app or API with Express JS is mainly done for high-quality error handling. Error handling is one of the most underlooked yet important aspects of creating good code for your end users. In this article, we will discuss the Express JS error handling best practices and help you manage errors efficiently.

How Express JS error handling works

Expresses built-in error handling

Express JS performs the basic error handling task by default. When writing synchronous code Express will catch your errors and automatically create a 500 response with the error message.

app.get("/", (req, res) => {
	throw new Error("My error message here.");
})

The response will look something like this.

Express js error handling.webp

Express JS error handling middleware

The problem

Although the method shown above will work for basic examples using synchronous code, however, asynchronous code is a whole different beast. When the following code is used, the app does not automatically handle errors and will crash.

app.get("/", async (req, res) => {
	throw new Error("My error message here.");
})

The reason behind this is when a request is handled under the hood, express runs a try-catch statement in an error handling middleware shown in the code below.

try {
       fn(req, res, next);
} catch (err) {
	 next(err);
}

If you have ever error handled using the asynchronous functions the issue should now be clear. When throwing an error in an async function, it returns a promise that has been rejected rather than directly calling throw in the try statement.

How do we solve this

The solution to this problem is to run the next function directly instead of throwing an error. This ensures that the error middleware is called with the error.

app.get("/", async (req, res) => {
	return next(new Error("My error message here."))
})

If you are using promise chaining you can also put the next function in the catch statement.

app.get("/", async (req, res) => {
	promise()
		.then(() => {
			// do a thing	
		})
		.catch(next)
})

Writing your middleware

When writing your app you may need some more logic to handle your errors such as error loggers and custom error messages to your client. An error middleware is a function that will include error, request, response, and the next function as parameters.

An example of a middleware is an error logger. In its simplest form, it will log the error to the console and then pass the error to the next middleware. Below is a simple example of how you may implement this.

const errorLogger = (err, req, res, next) => {
	console.error(err.stack);
	next(err);
}

To use the middleware you can pass it into the “app.use” method after that you can include your routes.

Note: this order is essential.

// use your routes in your app
app.use(routers)
// then use your middlewares
app.use(errorLogger)

Another middleware that you can also use is an error handler that controls the error sent to the client. This can be important if you want to respond with an error in a specific format and response type. The error handler middleware will be at the end of the middleware error chain since it has to be run after all other middleware.

const errorHandler = (err, req, res, next) => {
	const statusCode = err.statusCode ?? 500;

	return res.status(statusCode ?? 500).json({
		error: statusCode,
		message: err.message
	})
}

You can include this handler by using it in your app below the error logger handler in the code.

Custom Errors

Custom error types are very useful when you write specific functionality or include specific attributes such as status codes in your error.

class CustomError extends Error {
	constructor(reason) {
		this.name = this.constuctor.name;
		this.message = `Custom error occured due to ${reason}.`;
		this.statusCode = 500;
	}
}

Express JS error handling 404

You can catch all responses that are not sent by adding a middleware at the end of the chain with a request, response, and next parameters.

const notFoundHandler = (req, res, next) => {
res.status(404).json({
		error: 404,
		message: "Route not found."
	})
}

app.use(notFoundHandler);

If you have a custom error handler middleware you can alternatively create a custom error type with a status code of 404 and an appropriate message.

Real-world example

To understand how you can use these techniques in a real project it’s good to practice by creating an example project. In this example, we will show how you can create a book API using scalable error-handling techniques.

Creating our middleware

As mentioned in the previous section, we can create middleware to handle the errors. In this example, we will use 3 main error-handling middleware. This will include middleware for logging errors, handling errors, and handling 404 errors.

We will put the middleware in a directory “src/middlewares”.
First, we have an error logger. This is almost the same as in the previous example and is nothing fancy. You can also save the output in a file.

// "src/middlewares/errorLogger.js"

const errorLogger = (err, req, res, next) => {
	// logs error to console and then passes to next middleware
  console.error(err.stack);
  next(err);
}

module.exports = errorLogger;

Next, we have the error handler. This middleware will take an error with a message and potential status code and return it to the client in a JSON format. This will be the last middleware in the chain as it is always the last thing to run.

// "src/middlewares/errorHandler.js"

const errorHandler = (err, req, res, next) => {
	// if no status or message in error use default 500 code and message
	const statusCode = err.status ?? 500;
	const message = err.message || "Something went wrong.";

	// returns error status code and message
	return res.status(statusCode).json({
		error: statusCode,
		message: message
	})
}

module.exports = errorHandler;

The last error middleware is a 404 not found error handler. We can do this by passing an error with the status code 404 to the error handler. To do this we will need to create a custom error with the status code 404 and the message “Not found”. We can put all our custom errors in the directory “src/helper/errors”.

// "src/helpers/errors/NotFoundError.js"
class NotFoundError extends Error {
  constructor() {
    super();
    this.status = 404;
    this.message = "Not found."
  }
}

module.exports = NotFoundError;

The middleware can now simply pass an instance of a not found error to the error middleware.

// "src/middlewares/errorNotFound.js"

const NotFoundError  = require("../helpers/errors/NotFoundError")

const errorNotFound = (req, res, next) => next(new NotFoundError();

module.exports = errorNotFound;

To use these routes we can simply run the use method on the express app. In our app, we will also use the built-in express JSON middleware and the router at the address “/api”. Again, while creating this make sure the ordering is correct as the flow of the middleware is important.

const express = require("express");
const errorHandler = require("./middlewares/errorHandler");
const errorLogger = require("./middlewares/errorLogger");
const errorNotFound = require("./middlewares/errorNotFound");
const routes = require("./routes");

const app = express();

app.use(express.json());

app.use("/api", routes);

app.use(
  errorNotFound, 
  errorLogger, 
  errorHandler
);

module.exports = app;

The router

We put our router in the directory “src/routes”. Since we are only using one route in this example we will just put all the code in “src/routes/index.js” but it is best practice to put each route and controller into directories.

First, let us create the route with no Express JS error handling. We can use the “express.Router“ method to create a router and export it as the default value from the file.

const express = require("express");
const fs = require('fs');

const router = express.Router();

module.exports = router;

For this API we will create the route “/find”, which will take a post request with a JSON body containing a filename and title for the book. We will store JSON files in a “data” directory and read them with the inbuilt fs library in node js. The fs.readFile method takes the encoding and a callback with an error and data parameter in the file path.

fs.readFile(`data/${filename}.json`, 'utf8', (err, data) => {/*code*/})

In the callback, we will first parse the data as a JSON object. We can do this with the JSON.parse method as shown below.

const json = JSON.parse(data);

We now need to filter the data for books with a given title. We can use the filter method that you can call on arrays in JavaScript.

const books = json.books.filter(
  val => val.title.toLowerCase().includes(title.toLowerCase()));

Lastly, we return a response with a 200 status code and JSON object of the books.

return res.status(200).json({
  books
})

All together your file with no error handling should look as follows.

// "src/routes/index.js"

const express = require("express");
const fs = require('fs');

const router = express.Router();

router.post("/find", async (req, res, next) => {
  const {filename, title} = req.body;
    
  fs.readFile(`data/${filename}.json`, 'utf8', (err, data) => {
    const json = JSON.parse(data);

    const books = json.books.filter(
	    val => val.title.toLowerCase().includes(title.toLowerCase()));
	
	  return res.status(200).json({
      books
    })
  });
})

module.exports = router;

Now if we send a request with fields that won’t cause an error when we get a response that looks like the following.

Express js error handling best practices.webp

Adding errors

There are 3 main places in this code where we may want to add error handling. The first will be to validate that the body does include the required parameters. We could resolve this directly in the route by checking if the parameters exist. A better way to do this is by creating a function that returns a middleware to check on the existence of the required parameters. The reason we do this is that this functionality will likely be used all over the code in many routes.

First, we will create a new custom error in “helper/errors” called RequiredBodyError. This error will be in the fields that are not included in the constructor. It will then set the status code to 400 and set the message to “Request must include the fields: (names of fields)”. This is simply done in the example below.

class RequiredBodyError extends Error {
    constructor(notIncludedFields) {
        super();
        this.status = 400;
        this.message = `Request must include the fields: ${notIncludedFields.join(', ')}.`;
    }
}

module.exports = RequiredBodyError;

We have our custom error that will create the function which will eventually create the middleware. To do this we will take in an array called fields which are the required fields and then check if the body has all of the fields. If the body doesn’t have all the fields it will run the next error middleware with a RequiredBodyError with all the missing fields.

const RequiredBodyError = require("../helpers/RequiredBodyError");
const requiredFields = (fields) => {
  return (req, _res, next) => {
    const missingFields = [];
    const keys = Object.keys(req.body); // Included fields

		// Checks if every required field is in the body
    for(const field of fields)
      if(!keys.includes(field))
        missingFields.push(field)

		// If there are missing fields then run next error middleware
    if(missingFields.length)
      return next(new RequiredBodyError(missingFields));
    
		// If no missing fields then run router code
    return next();
  }
}

module.exports = requiredFields;

You can now go back to the router code and add this new functionality. You can add this function as a parameter to the “router.post” method just before the controller code with an array of required fields. When done correctly the code will look something like the following.

router.post("/find", requiredFields(["filename", "title"]), async (req, res, next) => {

If you request this route with no fields it should give an appropriate 400 response with a reason for the error.

Express js error handling 404.webp

The next 2 errors are very easy to handle. The first is just checking if there is an error reading the file. To do this we just check if the error parameter is not undefined and if so, return an error.

fs.readFile(`data/${filename}.json`, 'utf8', (err, data) => {
	if(err)
    return next(new Error(`Error reading file ${filename}.`));

The last error will check if the JSON can be parsed and whether the JSON is in the correct format. This can simply be done with a try-catch statement. In the catch, we will just return an error with no message since it’s just a standard 500 error and we just want to signal that something went wrong. Once all error handling is implemented the final express js route error handling code will look like the following.

// src/routes/index.js

const express = require("express");
const fs = require('fs');
const requiredFields = require("../middlewares/requiredFields");

const router = express.Router();

// Post request at /find with a requiredFileds middleware
router.post("/find", requiredFields(["filename", "title"]), async (req, res, next) => {
	// Used fields  
	const {filename, title} = req.body;
    
  fs.readFile(`data/${filename}.json`, 'utf8', (err, data) => {
		// If error when reading the file return an error
    if(err)
      return next(new Error(`Error reading file ${filename}.`));

    try {
			// Parse file
      const json = JSON.parse(data);

      const books = json.books.filter(
        val => val.title.toLowerCase().includes(title.toLowerCase()));

			// Send response
      return res.status(200).json({
        books
      })
    } catch {
			// If could not parse file then return an error
      next(new Error());
    }
  });
})

module.exports = router;

If we now send a request with a file that does not exist, we get a response that looks like the following.

Express js route error handling.webp

If you send a request with a file that is not formatted correctly you will get a response that looks like the following.

A Guide to Error Handling in Express.js.webp

Conclusion

In this article, we explored the different approaches to error handling using middleware, custom errors, and async functions. We not only saw where the server can crash but also why it crashes if not handled correctly in async functions. Finally, we looked at how 404 errors can be handled and how we can cohesively implement it with the middleware and custom errors.

With this information, you can now create scalable projects that follow best practices when it comes to express error handling. Also, you are equipped with the skills to implement the ideas since we went through a guided example using all the concepts together.

Понравилась статья? Поделить с друзьями:
  • Ошибка 403 просьба не могла быть удовлетворена
  • Ошибка 404 вконтакте
  • Ошибка 404 dropbox что делать
  • Ошибка 404 not found как устранить
  • Ошибка 403 пример