denali-js/core

View on GitHub
app/actions/error.ts

Summary

Maintainability
A
1 hr
Test Coverage
import * as assert from 'assert';
import Action from '../../lib/runtime/action';
import Logger from '../../lib/runtime/logger';
import JSONParser from '../../lib/parse/json';
import { lookup } from '../../lib/metal/container';

/**
 * The default error action. When Denali encounters an error while processing a request, it will
 * attempt to hand off that error to the `error` action, which can determine how to respond. This is
 * a good spot to do things like report the error to an error-tracking service, sanitize the error
 * response based on environment (i.e. a full stack trace in dev, but limited info in prod), etc.
 *
 * @export
 * @class ErrorAction
 * @extends {Action}
 */
export default class ErrorAction extends Action {

  get originalAction(): string {
    return this.request._originalAction;
  }

  logger = lookup<Logger>('app:logger');
  parser = lookup<JSONParser>('parser:json');

  /**
   * Respond with JSON by default
   */
  async respond({ params }: any) {
    let error = params.error;
    assert(error, 'Error action must be invoked with an error as a param');
    // Print the error to the logs
    if ((!error.status || error.status >= 500) && this.config.environment !== 'test') {
      this.logger.error(`Request ${ this.request.id } errored:\n${ error.stack || error.message }`);
    }
    // Ensure a default status code of 500
    error.status = error.statusCode = error.statusCode || 500;
    // If debugging info is allowed, attach some debugging info to standard
    // locations.
    if (this.config.getWithDefault('logging', 'showDebuggingInfo', this.config.environment !== 'production')) {
      error.meta = error.meta || {};
      Object.assign(error.meta, {
        stack: error.stack.split('\n'),
        action: this.originalAction
      });
    // Otherwise, sanitize the output
    } else {
      if (error.statusCode === 500) {
        error.message = 'Internal Error';
      }
      delete error.stack;
    }
    if (this.request.accepts('html') && this.config.environment !== 'production') {
      this.render(error.status, error, { view: 'error.html' });
    } else {
      this.render(error.status, error);
    }
  }

}