Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Expressの冗長なエラー処理を簡潔にする

More than 1 year has passed since last update.

初投稿です。

今までExpressのエラー処理は以下のように書いてました。
(例:必須のリクエストパラメータのチェック)

const { username } = req.body;
if (!username) {
  const err = new Error('username is required');
  console.log(err);
  res.status(400).send({ error: err });
}

パラメータの個数分、同様の処理を書いていて冗長だなぁと感じていました。

エラー処理ミドルウェア関数

Express でのエラー処理にエラーハンドリングの方法が書いてありました。

err, req, res, nextの4つの引数を持つミドルウェア関数を定義して、全てのミドルウェアの最後で呼び出します。

function logErrors(err, req, res, next) {
  console.error(err.stack);
  next(err);
}

function errorHandler(err, req, res, next) {
  res.status(500);
  res.send({ error: err });
}

app.use(logErrors);
app.use(errorHandler);

logErrors関数はエラーのログを出力します。
errorHandler関数はクライアントにエラーレスポンスを返します。

そして、エラーを投げる側ではnext関数にエラーオブジェクトを渡します。

const { username } = req.body;
if (!username) {
  const err = new Error('username is required');
  next(err);
}

これでエラーログ出力とエラーレスポンス返却をエラー処理ミドルウェアに任せることができました。

しかし、今のままではerrorHandlerで常にステータスコードが500のエラーレスポンスが返されてしまいます。なので、ちょっと変えます。

function errorHandler(err, req, res, next) {
  res.status(err.statusCode || 500);
  res.send({ error: err });
}
const { username } = req.body;
if (!username) {
  const err = new Error('username is required');
  err.statusCode = 400;
  next(err);
}

これでステータスコードが400のエラーレスポンスを返せるようになります。

ステータスコードの設定

毎回、エラーオブジェクトにステータスコードを設定するのは面倒臭いです。
CustomErrorクラスかboomを導入すると、ステータスコードの設定が簡潔になります。

CustomErrorクラス

class CustomError extends Error {
  constructor(message, statusCode) {
    super(message);
    this.statusCode = statusCode;
  }
}
if (!username) next(new CustomError('username is required', 400));

ワンライナーで書けました。

boom

hapijs/boom
boomはHTTPのエラーオブジェクト返すモジュール群です。

Boom.badRequest('invalid query')

上のコードは以下のオブジェクトを返します。

{
    "statusCode": 400,
    "error": "Bad Request",
    "message": "invalid query"
}

コードを見ればどんなエラーかわかるのでいいですね。
badRequestの他にもunauthorizedやnotFoundなど基本的なエラーが揃っています。

boomを使って書くと、こうなります。

if (!username) next(Boom.badRequest('username is required'));

まとめ

  • エラーミドルウェア関数を用いることで、エラーログ出力とエラーレスポンスの返却処理を共通化することができました
  • CustomErrorクラス(またはboom)を用いることで、ステータスコードの設定が簡単になりました

参考

azujuuuuuun
フロントエンドが好きです。 React / React Native / TypeScript / Nuxt.js / Node.js / Express
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away