0

In other words, should the raising of an HTTP 4xx code be considered an error, and should the job of sending an HTTP 4xx code to a client be delegated to an error handler?

Or is it simpler to just send such codes from whichever local code block we happen to be in, when the need arises, instead of delegating this to an error handler?

I'm leaning towards sending them from local code blocks rather than delegating, since it seems that

  1. HTTP responses are easy to send, i.e., handle, from a local code block,
  2. 4xx HTTP codes may not be "real" errors if you use a narrow-enough notion of error,
  3. the exact HTTP message and code can vary, and it'd be a hassle to account for many such combinations in an error handler.

Thoughts?

Asker
  • 109
  • 5

2 Answers2

1

A common way to send error responses in Express is to use middlewares. The benefit of doing it through a middleware rather than from a specific function is mostly about code duplication.

In fact, if you just started the project, your needs may be relatively basic: for instance if it's an API, you may want to send a simple HTTP 403 response with a body such as:

{
    "error": "forbidden"
}

Over time, however, you may need to add other features. For instance, the error message may need to take in account the HTTP Accept header and send either JSON or XML. Or you may want to add an unique identifier in case the user of the API wants to report an issue. Or add a link to the documentation.

{
    "error": "forbidden",
    "id": "E-PAO-1",
    "description": "You cannot access the resource; it is reserved for premium accounts.",
    "details": "https://example.com/api/documentation/errors/E-PAO-1",
    "support-id": "9229171a-42e2-41f5-aa05-1a14ca5df062"
}

When you use a middleware, all you need to do is to modify the middleware (for example by adding if (req.accepts('json')) ... to select between JSON and XML). If, on the other hand, you rely on the responses generated locally, you'll end up refactoring them to call a common function. While this would solve the code duplication problem, it is a bit unfortunate to use a home-grown mechanism, when you can rely on the middleware to do the exact same thing.

Arseni Mourzenko
  • 134,780
  • 31
  • 343
  • 513
0

OK, I just realized that I've been horribly confused.

In my original post, I said:

  1. the exact HTTP message and code can vary, and it'd be a hassle to account for many such combinations in an error handler.

This was written under the stupidly wrong assumption that an err object can't have multiple fields.

So, incredibly, I forgot that it is possible the send an err with multiple fields such as

{
  http: "401"
  message: "Invalid auth token"
}

which makes it trivial to send HTTP 4xx codes on a case-by-case basis using a middleware, e.g.,

const errorHandler = (err, req, res, next) => {
  if (typeof(err) === 'object' && 'http' in err) {
    return res.status(err.http).json({ error: err.message })
  }
  // etc. etc. etc...
}

Given the above, it's obvious to me now that using an error-handling middleware is the right way to go, because my main concern (which, in hindsight, I did a poor job of making explicit) has been addressed.

Namely, error-handling middleware are flexible and easy to use because the err object can contain multiple data fields, and these fields can be arbitrarily chosen.

I'm kicking myself for missing something so basic and blindingly obvious.

Thanks to Arseni for his answer, whose example code made me realize my error.

Asker
  • 109
  • 5