Routing-controllers: question: how handle ValidationErrors

Created on 23 Feb 2017  路  6Comments  路  Source: typestack/routing-controllers

is there a way to handle ValidationErrors, which are throwed by the class-validator?
i'm getting following response if i send invalid data:

{
   "name":"BadRequestError",
   "message":"Invalid body, check 'details' property for more info.",
   "stack":"Error\n at BadRequestError.HttpError [as constructor] (",
   "httpCode":400,
   "details":[
      {
         "target":{ ... },
         "value":"abc",
         "property":"email",
         "children":[ ],
         "constraints":{
            "isEmail":"email must be an email"
         }
      }
   ]
}

and i need the validation result in the following structure:

{
  "ValidationErrors":[
    {
      "target":{ ... },
      "value":"abc",
      "property":"email",
      "children":[ ],
      "constraints":{
        "isEmail":"email must be an email"
      }
    }
  ]
}

Maybe some kind of ValidationErrorMiddleware?

question

Most helpful comment

Create you own error middleware to map the errors to your structure:

This is a sample which I used in my project:

import { ErrorMiddlewareInterface, MiddlewareGlobalAfter, HttpError } from "routing-controllers";
import { ValidationError } from "class-validator";
import * as express from "express";

/**
 * Express middleware to catch all errors throwed in controlers.
 * Should be first in error chain as it sends response to client.
 * 
 * @export
 * @class CustomErrorHandler
 * @implements {ErrorMiddlewareInterface}
 */
@MiddlewareGlobalAfter()
export class CustomErrorHandler implements ErrorMiddlewareInterface {

    /**
     * Error handler - sets response code and sends json with error message.
     * Handle: standard node error, HttpError, ValidationError and string.
     * 
     * @param {any} error An throwed object (error)
     * @param {express.Request} req The Express request object
     * @param {express.Response} res The Express response object
     * @param {express.NextFunction} next The next Express middleware function
     */
    public error(error: any, _req: express.Request, res: express.Response, _next: express.NextFunction) {
        let responseObject = {} as any;

        // if its an array of ValidationError
        if (Array.isArray(error) && error.every((element) => element instanceof ValidationError)) {
            res.status(400);
            responseObject.message = "You have an error in your request's body. Check 'errors' field for more details!";
            responseObject.errors = error;
            // responseObject.details = [];
            // error.forEach((element: ValidationError) => {
            //     Object.keys(element.constraints).forEach((type) => {
            //         responseObject.details.push(`property ${element.constraints[type]}`);
            //     });
            // });
        } else {
            // set http status
            if (error instanceof HttpError && error.httpCode) {
                res.status(error.httpCode);
            } else {
                res.status(500);
            }

            if (error instanceof Error) {
                const developmentMode: boolean = process.env.NODE_ENV === "development";

                // set response error fields
                if (error.name && (developmentMode || error.message)) { // show name only if in development mode and if error message exist too
                    responseObject.name = error.name;
                }
                if (error.message) {
                    responseObject.message = error.message;
                }
                if (error.stack && developmentMode) {
                    responseObject.stack = error.stack;
                }
            } else if (typeof error === "string") {
                responseObject.message = error;
            }
        }

        // send json only with error
        res.json(responseObject);
    }
}

Load the middleware and disable the default error handler:

useExpressServer(app, {
    defaultErrorHandler: false,
    middlewares: [
         __dirname + "/../middlewares/errors/custom-error.js",  // register error handler
    ]
});

All 6 comments

Create you own error middleware to map the errors to your structure:

This is a sample which I used in my project:

import { ErrorMiddlewareInterface, MiddlewareGlobalAfter, HttpError } from "routing-controllers";
import { ValidationError } from "class-validator";
import * as express from "express";

/**
 * Express middleware to catch all errors throwed in controlers.
 * Should be first in error chain as it sends response to client.
 * 
 * @export
 * @class CustomErrorHandler
 * @implements {ErrorMiddlewareInterface}
 */
@MiddlewareGlobalAfter()
export class CustomErrorHandler implements ErrorMiddlewareInterface {

    /**
     * Error handler - sets response code and sends json with error message.
     * Handle: standard node error, HttpError, ValidationError and string.
     * 
     * @param {any} error An throwed object (error)
     * @param {express.Request} req The Express request object
     * @param {express.Response} res The Express response object
     * @param {express.NextFunction} next The next Express middleware function
     */
    public error(error: any, _req: express.Request, res: express.Response, _next: express.NextFunction) {
        let responseObject = {} as any;

        // if its an array of ValidationError
        if (Array.isArray(error) && error.every((element) => element instanceof ValidationError)) {
            res.status(400);
            responseObject.message = "You have an error in your request's body. Check 'errors' field for more details!";
            responseObject.errors = error;
            // responseObject.details = [];
            // error.forEach((element: ValidationError) => {
            //     Object.keys(element.constraints).forEach((type) => {
            //         responseObject.details.push(`property ${element.constraints[type]}`);
            //     });
            // });
        } else {
            // set http status
            if (error instanceof HttpError && error.httpCode) {
                res.status(error.httpCode);
            } else {
                res.status(500);
            }

            if (error instanceof Error) {
                const developmentMode: boolean = process.env.NODE_ENV === "development";

                // set response error fields
                if (error.name && (developmentMode || error.message)) { // show name only if in development mode and if error message exist too
                    responseObject.name = error.name;
                }
                if (error.message) {
                    responseObject.message = error.message;
                }
                if (error.stack && developmentMode) {
                    responseObject.stack = error.stack;
                }
            } else if (typeof error === "string") {
                responseObject.message = error;
            }
        }

        // send json only with error
        res.json(responseObject);
    }
}

Load the middleware and disable the default error handler:

useExpressServer(app, {
    defaultErrorHandler: false,
    middlewares: [
         __dirname + "/../middlewares/errors/custom-error.js",  // register error handler
    ]
});

@d-bechtel is @19majkel94 solution fixes your issue?

closing this, please @d-bechtel let use know if you have something to add

can i handle ValidationErrors using Koa instead of express?

Sorry for commenting on a closed issue. Thought this issue would be appropriate rather than opening a new one.

I tried the above mentioned example and it did't work. Did a small sample though following it. Would like to clarify if this approach is correct. Not sure about the "BadRequestError" value, because I am not sure if this "BadRequestError" is specific for class-validator errors.

sample

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

humbertowoody picture humbertowoody  路  4Comments

azaslonov picture azaslonov  路  5Comments

xujif picture xujif  路  6Comments

circy picture circy  路  3Comments

AleskiWeb picture AleskiWeb  路  4Comments