server/api/utils/errors.js

  1. /**
  2. * Reusable API errors.
  3. *
  4. * @module server/api/utils/errors
  5. */
  6. const util = require('util');
  7. /**
  8. * An API error.
  9. *
  10. * When thrown from an API route or middleware, an error of this type will
  11. * automatically be serialized as JSON and the HTTP response will have the
  12. * correct status code.
  13. *
  14. * @class
  15. * @extends Error
  16. * @property {string} name - The type of error.
  17. * @property {number} status - The HTTP status code to respond with when this error occurs.
  18. * @property {string} code - A code identifying the error (e.g. `category.whatWentWrong`).
  19. * @property {string} message - A description of the problem.
  20. */
  21. function ApiError(status, code, message) {
  22. Error.captureStackTrace(this, this.constructor);
  23. this.name = this.constructor.name;
  24. this.status = status;
  25. this.code = code;
  26. this.message = message;
  27. }
  28. util.inherits(ApiError, Error);
  29. exports.ApiError = ApiError;
  30. /**
  31. * Returns an HTTP 401 Unauthorized error.
  32. *
  33. * @param {string} code - A code identifying the error (e.g. `auth.whatWentWrong`).
  34. *
  35. * @param {string} message - A description of the problem.
  36. *
  37. * @returns {ApiError} An API error.
  38. */
  39. exports.unauthorized = function(code, message) {
  40. return new ApiError(401, code, message || 'Authentication is required to access this resource. Authenticate by providing a Bearer token in the Authorization header.');
  41. };
  42. /**
  43. * Returns an HTTP 401 Unauthorized error with the `auth.missingAuthorization` code due to missing credentials.
  44. * @returns {ApiError} An API error.
  45. */
  46. exports.missingAuthorization = function() {
  47. return exports.unauthorized('auth.missingAuthorization');
  48. };
  49. /**
  50. * Returns an HTTP 401 Unauthorized error with the `auth.malformedAuthorization` code due to malformed credentials (e.g. a badly formatted Authorization header).
  51. * @returns {ApiError} An API error.
  52. */
  53. exports.malformedAuthorization = function() {
  54. return exports.unauthorized('auth.malformedAuthorization', 'The Authorization header is not in the correct format. It should be "Authorization: Bearer TOKEN".');
  55. };
  56. /**
  57. * Returns an HTTP 401 Unauthorized error with the `auth.invalidAuthorization` code due to invalid credentials (e.g. an expired JWT).
  58. * @returns {ApiError} An API error.
  59. */
  60. exports.invalidAuthorization = function() {
  61. return exports.unauthorized('auth.invalidAuthorization', 'The Bearer token supplied in the Authorization header is invalid or has expired.');
  62. };
  63. /**
  64. * Returns an HTTP 403 Forbidden error.
  65. *
  66. * The message defaults to "You are not authorized to access this resource. Authenticate with a user account that has more privileges.".
  67. *
  68. * @param {string} [code=auth.forbidden] - A code identifying the error.
  69. *
  70. * @param {string} [message] - A description of the problem.
  71. *
  72. * @returns {ApiError} An API error.
  73. */
  74. exports.forbidden = function(code, message) {
  75. return new ApiError(403, code || 'auth.forbidden', message || 'You are not authorized to access this resource. Authenticate with a user account that has more privileges.');
  76. };
  77. /**
  78. * Returns an HTTP 404 Not Found error.
  79. *
  80. * The message defaults to "No resource was found at this verb and URI.".
  81. *
  82. * @param {string} [code=resource.notFound] - A code identifying the error.
  83. *
  84. * @param {string} [message] - A description of the problem.
  85. *
  86. * @returns {ApiError} An API error.
  87. */
  88. exports.notFound = function(code, message) {
  89. return new ApiError(404, code || 'resource.notFound', message || 'No resource was found at this verb and URI.');
  90. };
  91. /**
  92. * Returns an HTTP 404 Not Found error due to a missing resource.
  93. * @returns {ApiError} An API error.
  94. */
  95. exports.recordNotFound = function(name, id) {
  96. return exports.notFound('record.notFound', 'No ' + name + ' was found with ID ' + id + '.');
  97. };