Reputation: 315
I'm seeing some class-validator errors in an unexpected location. I would expect a more convenient format for dealing with errors, but perhaps I'm unaware of some graphQL tricks for dealing with objects in the extensions field...
While running NestJS sample/23-graphql-code-first, I see the following in the GraphQL playground:
With input:
addRecipe(newRecipeData: {
description: "too short"
title: "this field should fail for being too long"
ingredients: ["normal"]
}) {
title
}
}
I am returned:
"errors": [
{
"message": "Bad Request Exception",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"addRecipe"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"response": {
"statusCode": 400,
"message": [
"title must be shorter than or equal to 30 characters",
"description must be longer than or equal to 30 characters"
],
"error": "Bad Request"
},
"status": 400,
"message": "Bad Request Exception",
"stacktrace": [
"Error: Bad Request Exception",
" at ValidationPipe.exceptionFactory nest/sample/23-graphql-code-first/node_modules/@nestjs/common/pipes/validation.pipe.js:78:20)",
...
]
}
}
}
],
"data": null
}
These errors are deeply nested, and "Bad Request Exception" is not so useful. Is this working as intended?
Upvotes: 15
Views: 18200
Reputation: 2824
If you are looking for how to strip the stack trace off of the GraphQL Error you just have to make debug field as false
GraphQLModule.forRoot<ApolloDriverConfig>({
driver: ApolloDriver,
debug: false, // set as ENV param
playground: true, // set as ENV param
autoSchemaFile: join(process.cwd(), 'src/schema.gql'),
})
If you set both debug
and playground
as ENV params to true
for dev
environment, you will not see the stack trace in prod.
Upvotes: -2
Reputation: 514
Here is my solution you could add error and ok objects to your @ObjectType
.
@ObjectType()
export class UserCreateOutput {
//can be null if error
@Field(() => User, { nullable: true })
user?: User;
@Field(() => Boolean)
ok?: boolean;
@Field(() => String, { nullable: true })
error?: string;
}
On .service.ts you could catch and show error as a return.
catch (error) { return { ok: false, error: 'Could not create account', //Your custom error message user: null, //Make sure that this object can be null :) };
Upvotes: -3
Reputation: 361
If you're using mercurius
, you can use this:
// In main.ts file, just register ValidationPipe like normal
app.useGlobalPipes(new ValidationPipe({ forbidUnknownValues: true }))
// In app.module.ts file, add this errorFormatter:
GraphQLModule.forRoot<MercuriusDriverConfig>({
...
errorFormatter: execution => {
const [error] = execution.errors // take first error
const originalError = error?.originalError
if (originalError instanceof HttpException)
return {
statusCode: originalError.getStatus(),
response: { data: originalError.getResponse() as any }
}
return { statusCode: 500, response: execution }
}
})
Upvotes: 8
Reputation: 335
The best solution is based on this official comment: creates your own formatError or formatResponse function.
I just used in this project on GitHub and it worked fine!
The change needs to be added to src/app.module.ts, by default.
My Sample:
import { GraphQLError, GraphQLFormattedError } from 'graphql';
GraphQLModule.forRoot({
autoSchemaFile: true,
debug: false,
formatError: (error: GraphQLError) => {
const graphQLFormattedError: GraphQLFormattedError = {
message: error?.extensions?.exception?.response?.message || error?.message,
};
return graphQLFormattedError;
},
}),
And now, I'm getting a formatted error response from GraphQL:
{
"errors": [
{
"message": [
"firstName must be longer than or equal to 1 characters",
"lastName must be longer than or equal to 1 characters"
]
}
],
"data": null
}
Upvotes: 27
Reputation: 1012
I ended up doing this in main.ts (although i'm sure there is a better solution)
app.useGlobalPipes(
new ValidationPipe({
exceptionFactory: (errors: ValidationError[]) => {
const error_messages = errors.map(error =>
Object.values(error.constraints),
);
return new BadRequestException(error_messages.toString());
},
forbidUnknownValues: false,
}),
);
Upvotes: 2
Reputation: 167
When you use Validation pipe you can change that behaviour:
app.useGlobalPipes(
new ValidationPipe({
exceptionFactory: errors => new BadRequestException(errors), // TODO: Use graphql errors instead
forbidUnknownValues: true,
}),
);
Upvotes: 1