2 years ago
#70048

NooNoo
Convenient format for validation errors
I'm developing application with next tech stack:
- Backend (NestJs, GraphQL)
- Frontend (React, Apollo^3.5.0)
I have REST and Gql apis. I'm stacked in defining errors format for both apis types: REST and Gql. How to make it universal.
I will explain my problem on real example. It's registration form.
Example
In frontend app I have simple react form with 2 fields: email and password. Of course, I do validation on both sides.
On client side:
- Email field should pass regexp
- Password field should have >6 characters
On backend side (class-validator decorators):
- Email ( @IsEmail, @UniqEmail - custom decorator, that is searching user with provided email in db )
- Password ( @MinLength(6) )
Problem
I want to find the easiest and flexible way (or format) of validation errors to provide them to the client side. To make a simple map and show them in ui.
I found solution but it seems to me weird (because of low typing level). On backend side I make a special errors formatting:
app.useGlobalPipes(
new ValidationPipe({
exceptionFactory: (errors) => {
// property - property that caused error
// constraints - type of error(minLength, uniq, ...)
const formatted = errors.map((error) => ({ property: error.property, constraints: error.constraints }));
return new BadRequestException(formatted);
},
}),
);
And format provided errors for gql:
formatError: (error) => {
if (GraphqlErrorFormatter.getErrorCode(error) === 'INTERNAL_SERVER_ERROR') {
return GraphqlErrorFormatter.formatInternalError(error);
}
return GraphqlErrorFormatter.formatError(error);
},
And map errors on client side in such way:
// Dictionary to map errors in current language
const map = {
email: {
uniq: 'Email is already registered',
},
password: {
minLength: 'Bla-bla-bla',
},
};
// MUTATION PROPS
onError: (err) => {
err.graphQLErrors.forEach((graphQLError) => {
graphQLError.extensions.response.message.forEach((message) => {
const { property, constraints } = message;
const [constraint] = Object.keys(constraints);
const errorMessage = map[property][constraint];
if (errorMessage) setFieldError(property, { message: errorMessage });
});
});
}
Other solutions
- Gql union type for response payload approach (e.g. put errors in data key in resp object).
I know about this but I decided to use it for bussiness errors, not validation errors.
Question
What is your experience? What approach do you use in your applications? Thanks in advance for any answer.
graphql
nestjs
apollo-server
0 Answers
Your Answer