All files / app/util validation-result-handler.ts

88.46% Statements 23/26
82.35% Branches 14/17
100% Functions 2/2
88.46% Lines 23/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 961x 1x 1x                                                                                       1x       14x   14x   14x                   14x 14x     14x     452x 265x 265x   187x 187x     452x     452x 452x 452x 60x   60x   392x   392x        
import debug from 'debug';
import {validationResult} from 'express-validator';
import {InvalidRequestError} from '@app/errors';
import {RequestHandler, Request} from 'express';
 
export interface ValidationResultHandlerOptions {
  /**
   * Key which should be used for logging.
   *
   * For example:
   *
   * By calling this method like this:
   * ```typescript
   * validationResultHandler('my-server:module', '...');
   * ```
   * the method will use the following for logging if
   * an ip requested an action and if the validation succeeded.
   * ```typescript
   * debug('my-server:module');
   * ```
   * and the following if the validation failed
   * ```typescript
   * debug('my-server:module:error');
   * ```
   */
  debugScope: string;
 
  /**
   * Short name for the request.
   *
   * This will be used in the logging messages to
   * indicate what action was requested.
   *
   * If this option is a function, the function will be called with
   * the request object of the request. The function should then return
   * a string.
   */
  requestName: ((req: Request) => string) | string;
}
 
/**
 * Creates a request handler which handles the `validationResult` of the
 * request. The request handler expects that the request is already validated.
 * @param options - The options with which the validationResultHandler
 *  should be created
 */
export const createValidationResultHandler: (
  options: ValidationResultHandlerOptions
) => RequestHandler = (options: ValidationResultHandlerOptions) => {
  // Check if options are defined
  Iif (!options) {
    throw new Error('The options object has to be provided');
  } else Iif (!options.debugScope || typeof options.debugScope !== 'string') {
    throw new Error('options.debugScope has to be a non empty string');
  } else Iif (!options.requestName ||
    (
      typeof options.requestName !== 'string' &&
      typeof options.requestName !== 'function'
    )) {
    throw new Error('options.request has to be a non empty string or ' +
      'a function which will return a string');
  }
 
  // Create debug methods
  const log = debug(options.debugScope);
  const error = debug(`${options.debugScope}:error`);
 
  // Return the request handler
  return (req, _res, next) => {
    let userIdentifierLog: string;
    let userIdentifier: number | string;
    if (req.user !== undefined) {
      userIdentifierLog = 'User %d ';
      userIdentifier = req.user.id;
    } else {
      userIdentifierLog = 'IP %s ';
      userIdentifier = req.ip;
    }
 
    const requestName = typeof options.requestName === 'string' ?
        options.requestName : options.requestName(req);
 
    log(userIdentifierLog + 'requested: %s', userIdentifier, requestName);
    const errors = validationResult(req);
    if (!errors.isEmpty()) {
      error(`Request of ${userIdentifierLog} failed validation for: %s`,
          userIdentifier, requestName);
      throw new InvalidRequestError(errors);
    } else {
      log(`Request of ${userIdentifierLog} passed validation for: %s`,
          userIdentifier, requestName);
      next();
    }
  };
};