Guidelines for Nestjs class-validator exception - implementing metadata information for @IsNotIn validator error handling

I have a NestJs data transfer object (dto) structured like this

import { IsEmail, IsNotEmpty, IsNotIn } from 'class-validator';
import { AppService } from './app.service';
const restrictedNames = ['Name Inc', 'Acme Inc'];
class DTO {
  @IsNotEmpty()
  name: string;
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @IsNotIn(restrictedNames)
  orgName: string;
}

I've implemented an exception filter to provide detailed error messages for failed validations.

app.useGlobalPipes(
new ValidationPipe({
  exceptionFactory: (validationErrors: ValidationError[] = []) => {
    console.log(validationErrors);
    return new BadRequestException({
      statusCode: HttpStatus.BAD_REQUEST,
      message: validationErrors.reduce((acc, error) => {
        acc[error.property] = Object.keys(error.constraints).map(
          (failed) => ({
            failedValidation: failed,
            message: error.constraints[failed],
          }),
        );
        return acc;
      }, {}),
      error: 'validation',
    });
  },
}),

);

The current error response looks something like this

{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc"}]},"error":"validation"}

However, I'd like the error message to include specific details about reserved keywords in case of the @NotIn validation failure, presented as a separate key:

{"statusCode":400,"message":{"email":[{"failedValidation":"isEmail","message":"email must be an email"}],"orgName":[{"failedValidation":"isNotIn","message":"orgName should not be one of the following values: Name Inc, Acme Inc", "data":{"reservedKeywords":["Name Inc","Acme Inc"]}}]},"error":"validation"}

Unfortunately, the existing exception Filter block does not retrieve the constraint values along with the decorator metadata.

message: validationErrors.reduce((acc, error) => {
        acc[error.property] = Object.keys(error.constraints).map(
          (failed) => ({
            failedValidation: failed,
            message: error.constraints[failed],
          }),
        );
        return acc;
      }, {}),
      error: 'validation',
    });

Answer №1

Based on my understanding, there isn't a built-in feature for automatically returning metadata when working with blacklisted values. However, you can utilize the context property to handle specific error types.

const restrictedNames = ['Name Inc', 'Acme Inc'] as const;
class DTO {
  @IsNotEmpty()
  name: string;
  @IsEmail()
  email: string;

  @IsNotEmpty()
  @IsNotIn(restrictedNames, { context: { reservedKeywords: restrictedNames } }) // here
  orgName: string;

  // Constructor can be ignored for this illustration
  constructor(name: string, email: string, orgName: string) {
    this.name = name;
    this.email = email;
    this.orgName = orgName;
  }
}

To incorporate the conditional value in your transform function, make use of error.contexts

const transformedMessage = errors.reduce((acc, error) => {
  acc[error.property] = Object.keys(error.constraints).map((failed) => ({
    failedValidation: failed,
    message: error.constraints[failed],
    data: error.contexts && error.contexts[failed],
  }));
  return acc;
}, {});

Check out the customized output:

{
  "email": [
    {
      "failedValidation": "isEmail",
      "message": "email must be an email"
    }
  ],
  "orgName": [
    {
      "failedValidation": "isNotIn",
      "message": "orgName should not be one of the following values: Name Inc, Acme Inc",
      "data": {
        "reservedKeywords": [
          "Name Inc",
          "Acme Inc"
        ]
      }
    }
  ]
}

Note: Thanks for sharing the transform function - it's incredibly valuable!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Implementing advanced error handling using custom error messages with enums

I'm trying to use Zod to validate a gender field with z.nativeEnum(), but for some reason my custom error messages are not being applied: gender: z.nativeEnum(Gender, { invalid_type_error: 'Le sexe doit être homme ou femme.', ...

How can you reposition a component within the dom using Angular?

Just started learning Angular, so I'm hoping this question is simple :) Without getting too specific with code, I could use some guidance to point me in the right direction. I'm currently developing a small shopping list application. The idea i ...

Using sqlite3 on macOS Sierra is a powerful tool for

Each time I attempt to install sqlite3 on my Mac, I encounter the following error message: sh: node-pre-gyp: command not found npm WARN <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e095919d8ec4a596928692">[email p ...

The npm error message indicates that there is an issue with the transpileDependencies.map function

Every time I attempt to execute my program, this error pops up: https://i.stack.imgur.com/ANA0z.png Even after uninstalling and reinstalling node, the error persists. ...

What is the best way to access attributes from a div element?

I am currently working on extracting attributes from within a div tag, specifically the custom attributes of the first child element. I am using web scraping techniques with Node.js and Puppeteer. My goal is to retrieve the custom attributes data-ticker, d ...

Troubleshooting a Pulumi script in Azure using Typescript and encountering difficulties with function writing

My background is in using terraform, but now I am trying out Pulumi/typescript for the first time. In my codebase, I have two files - index.ts and blob.ts. The create function in blob.ts is responsible for creating a storage account, resource group, blob ...

Is it possible to share a file download using just Node.js without the need for express?

app.get('/retrieve', function(req, res){ const fileToRetrieve = `${__dirname}/documents-folder/dramaticpenguin.MOV`; res.download(fileToRetrieve); // Download the specified file. }); ...

Encountering a TypeError indicating that the asterisk is not functioning as a proper function

Whenever I run my server.js file, an error keeps popping up: TypeError: routing is not a function This occurs in the following line of code: routing(app); In my routing.js file, the content looks like this: // JavaScript source code var friends = requ ...

Points in an array being interpolated

I am currently working with data points that define the boundaries of a constellation. let boundaries = [ { ra: 344.46530375, dec: 35.1682358 }, { ra: 344.34285125, dec: 53.1680298 }, { ra: 351.45289375, ...

Mastering the utilization of API routes within the Next JS 13 App Router framework

As a newcomer to React JS and Next.js, I recently made the switch from using the Page Router API in Next.js to utilizing the new App Router introduced in Next.js 13. Previously, with the Page Router, creating a single GET request involved nesting your "JS ...

Observable in RxJS with a dynamic interval

Trying to figure out how to dynamically change the interval of an observable that is supposed to perform an action every X seconds has been quite challenging. It seems that Observables cannot be redefined once they are set, so simply trying to redefine the ...

Having trouble utilizing a function with an async onload method within a service in Angular - why does the same function work flawlessly in a component?

I successfully created a component in Angular that can import an Excel file, convert it into an array, and display its content as a table on the page. The current implementation within the component looks like this: data-import.compoent.ts import { Compo ...

Simultaneously Accessing Data from MongoDB and MySQL

I have been working on retrieving data from my MongoDB database, which contains chat conversations. The retrieval process is successful and I am getting the desired output. However, in my MongoDB database, I only store userIDs, so I need to fetch additiona ...

Is there a possibility for nock to collaborate with puppeteer?

Looking to utilize nock for mocking HTTP requests in puppeteer, but it requires nock to run in the same node process. Are there any solutions or workarounds available for achieving this? Nock offers powerful features that are beneficial for not only end-t ...

Facing Syntax Errors When Running Ng Serve with Ngrx

Currently, I am enrolled in an Angular course to gain proficiency in ngrx. In a couple of months, I will be responsible for teaching it, so I am refreshing my memory on the concept. Strangely, even after installing it and ensuring my code is error-free, er ...

Managing Events in EJS

I am currently utilizing the combination of Node.js, Express.js, and Ejs. Challenge In my particular scenario, I have 3 distinct layers: 1) clients-side.js ((node.js) 2) server.js (node.js) 3) front-end.ejs (ejs) Upon successful form submission, an e ...

Pulling the month name based on a specific year and week using Javascript

In my HTML form, there are two fields called Year and Week. When the user chooses a Year and Week from the dropdowns, I would like to show the corresponding Month Name for that specific year and week. Is there anyone who can assist me in retrieving the m ...

When working with Typescript and Vue.js, it's important to ensure that properties are initialized before

Check out the following code snippet: export default class PrimitiveLink extends Vue { style = { // Reset display: 'inline-block', textDecoration: 'none', outline: 'none', // Theme ...this.themeStyle ...

Utilize Array.push to add 2 new rows to a table using Angular 4

I have two arrays that are almost identical, except for two items which are the fakeDates: this.prodotti.push({ idAgreement: this.idAgreement,landingStatus: this.landingStatus, landingType: this.landingType, startDate: this.startDate, expirationDate: thi ...

Communication between Angular Controller and Nodejs Server for Data Exchange

Expanding on the solution provided in this thread, my goal is to implement a way to retrieve a response from the node server. Angular Controller $scope.loginUser = function() { $scope.statusMsg = 'Sending data to server...'; $http({ ...