3 * Copyright(c) 2014 Jonathan Ong
4 * Copyright(c) 2016 Douglas Christopher Wilson
11 * Module dependencies.
15 var deprecate = require('depd')('http-errors')
16 var setPrototypeOf = require('setprototypeof')
17 var statuses = require('statuses')
18 var inherits = require('inherits')
19 var toIdentifier = require('toidentifier')
26 module.exports = createError
27 module.exports.HttpError = createHttpErrorConstructor()
29 // Populate exports for all constructors
30 populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)
33 * Get the code class of a status code.
37 function codeClass (status) {
38 return Number(String(status).charAt(0) + '00')
42 * Create a new HTTP Error.
48 function createError () {
49 // so much arity going on ~_~
54 for (var i = 0; i < arguments.length; i++) {
55 var arg = arguments[i]
56 if (arg instanceof Error) {
58 status = err.status || err.statusCode || status
68 deprecate('non-first-argument status code; replace with createError(' + arg + ', ...)')
77 if (typeof status === 'number' && (status < 400 || status >= 600)) {
78 deprecate('non-error status code; use only 4xx or 5xx status codes')
81 if (typeof status !== 'number' ||
82 (!statuses[status] && (status < 400 || status >= 600))) {
87 var HttpError = createError[status] || createError[codeClass(status)]
93 : new Error(msg || statuses[status])
94 Error.captureStackTrace(err, createError)
97 if (!HttpError || !(err instanceof HttpError) || err.status !== status) {
98 // add properties to generic error
99 err.expose = status < 500
100 err.status = err.statusCode = status
103 for (var key in props) {
104 if (key !== 'status' && key !== 'statusCode') {
105 err[key] = props[key]
113 * Create HTTP error abstract base class.
117 function createHttpErrorConstructor () {
118 function HttpError () {
119 throw new TypeError('cannot construct abstract class')
122 inherits(HttpError, Error)
128 * Create a constructor for a client error.
132 function createClientErrorConstructor (HttpError, name, code) {
133 var className = name.match(/Error$/) ? name : name + 'Error'
135 function ClientError (message) {
136 // create the error object
137 var msg = message != null ? message : statuses[code]
138 var err = new Error(msg)
140 // capture a stack trace to the construction point
141 Error.captureStackTrace(err, ClientError)
143 // adjust the [[Prototype]]
144 setPrototypeOf(err, ClientError.prototype)
146 // redefine the error message
147 Object.defineProperty(err, 'message', {
154 // redefine the error name
155 Object.defineProperty(err, 'name', {
165 inherits(ClientError, HttpError)
166 nameFunc(ClientError, className)
168 ClientError.prototype.status = code
169 ClientError.prototype.statusCode = code
170 ClientError.prototype.expose = true
176 * Create a constructor for a server error.
180 function createServerErrorConstructor (HttpError, name, code) {
181 var className = name.match(/Error$/) ? name : name + 'Error'
183 function ServerError (message) {
184 // create the error object
185 var msg = message != null ? message : statuses[code]
186 var err = new Error(msg)
188 // capture a stack trace to the construction point
189 Error.captureStackTrace(err, ServerError)
191 // adjust the [[Prototype]]
192 setPrototypeOf(err, ServerError.prototype)
194 // redefine the error message
195 Object.defineProperty(err, 'message', {
202 // redefine the error name
203 Object.defineProperty(err, 'name', {
213 inherits(ServerError, HttpError)
214 nameFunc(ServerError, className)
216 ServerError.prototype.status = code
217 ServerError.prototype.statusCode = code
218 ServerError.prototype.expose = false
224 * Set the name of a function, if possible.
228 function nameFunc (func, name) {
229 var desc = Object.getOwnPropertyDescriptor(func, 'name')
231 if (desc && desc.configurable) {
233 Object.defineProperty(func, 'name', desc)
238 * Populate the exports object with constructors for every error class.
242 function populateConstructorExports (exports, codes, HttpError) {
243 codes.forEach(function forEachCode (code) {
245 var name = toIdentifier(statuses[code])
247 switch (codeClass(code)) {
249 CodeError = createClientErrorConstructor(HttpError, name, code)
252 CodeError = createServerErrorConstructor(HttpError, name, code)
257 // export the constructor
258 exports[code] = CodeError
259 exports[name] = CodeError
263 // backwards-compatibility
264 exports["I'mateapot"] = deprecate.function(exports.ImATeapot,
265 '"I\'mateapot"; use "ImATeapot" instead')