46
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Posted at

初投稿です。

今まで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)を用いることで、ステータスコードの設定が簡単になりました

参考

46
38
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
46
38

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?