#How to Show Custom Validation Errors in NestJS After Migrating to GraphQL

6 messages · Page 1 of 1 (latest)

surreal blaze
#

I’ve been working on migrating an API from REST to GraphQL, and I've run into an issue with input validation.

Before migrating, I used class-validator to validate the input data, which worked flawlessly. But after moving to GragpQL, the data is being validated by GraphQL itself, so now I end up with these generic error messages that I don't like.

For example:
name should be a string

mutation {
  createCustomer(input: {
    name: 999
    address: "addressaddress"
    city: "citycity"
    ice:"iceiceice"
    country:"countrycountry"
  }){
    data{
      name
    }
  }
}```

Instead of my validation error, I get a GraphQL error:

"String cannot represent a non string value: 999".

Now, my custom error messages aren't being shown at all.

I get why this is happening, but is there some way to show my errors again?

Edit: Forgot to add the Input class example

@InputType()
export class CreateCustomerInput {
@Field()
@IsNotEmpty()
@IsString()
name!: string;

@Field()
@IsNotEmpty()
@IsString()
address!: string;

@Field()
@IsNotEmpty()
@IsString()
city!: string;

@Field()
@IsNotEmpty()
@IsString()
ice!: string;

@Field()
@IsNotEmpty()
@IsString()
country!: string;

@Field({ nullable: true })
@IsOptional()
@IsString()
contact_name?: string;

@Field({ nullable: true })
@IsOptional()
@IsPhoneNumber('MA')
contact_phone?: string;

@Field({ nullable: true })
@IsOptional()
@IsEmail()
contact_email?: string;
}

elfin heath
#

You can format the error via the Apollo Driver option formatError.

For example:

@Module({
  imports: [    GraphQLModule.forRoot<ApolloDriverConfig>({
// ... other config
formatError: (error) => {
        const originalError = error.extensions?.originalError;
        
        // Handle class-validator errors specifically
        if (originalError instanceof BadRequestException) {
          return {
            message: 'Input validation failed!',
            code: 'VALIDATION_ERROR',
            extensions: {
              errors: originalError.getResponse(),
            },
          };
        }
        
        // Return other errors as-is
        return error;
      },

... or something to that effect.

Scott

surreal blaze
#

That isn't what I'm after. I messed around for hours, and I assume I can't achieve it. Because Graphql has to validate the input against the schema before it even reaches the class-validator decorators.

Thanks for helping.

elfin heath
#

Well, yeah. The API needs to be happy, before it will let a request through.

surreal blaze
#

Is what I'm asking for impractical?

elfin heath
#

Well, if you are expecting a response from the server like you did before with REST, then yes. GraphQL works differently than REST. It has its own type safety. field existence and nullable checks. If that is all ok, then it lets the request get to your business rule based validation checks. Your validation checks don't need to check for nullable or types safety, unless you need something more specialized than what GraphQL offers or just wish to be double certain. Lastly, the response will always be a GraphQL response type with the error. How that looks, is then up to you to decide.

This two level gating is much more precise, yet for the frontend developer, GraphQL is more flexible.

The best practice is to send your frontend the validation rules too and have the input checked, before it even gets to the server. It gives the user instant feedback and saves roundtrips to the server. But, with class-validator, that isn't practical, so you have to rework your frontend to work with GraphQL errors and you need to format them in the responses, so you can get a standard convention going that meets your frontend validation checking needs.

Here is an article about that.

Learn how to effectively handle GraphQL errors, including syntax errors, validation errors, resolver errors, and network errors. Get tips on error handling strategies and best practices.