How to unify validation for web and api?

Hey, at the beginning I want to say hello and thanks for all contributors and authors of such great framework Redwood is! :smile:

To the point. During doing a tutorial on Chapter 3 about forms I observed various validation differences which I believe can be improved from DX and UX point of view.

I. Different formats of validation. For the web components we’re able to define errors for each fields like that:

<TextField
  // other props
  validation={{ required: true }}
/>

For the api services implementation of similar validation looks like that:

export const createContact: MutationResolvers['createContact'] = ({
  input,
}) => {
  validate(input.message, 'message', { presence: { allowEmptyString: false } })

  return db.contact.create({
    data: input,
  })
}

So in that case we we want to require any field we have { required: true } for component and { presence: { allowEmptyString: false } for service. For more complex validation requirements this becomes only worse.


II. Default error message is different. In above example depends on source of error we’ve got:
For web this is: email is required
For api this is: Email must be present

In addition the way to overwrite these messages is too totally different and uses different logic.


III. Different behaviour of returned errors. For web by default validation on submit shows us all form errors. For api validation error returns only first error message. When you rely only on api validation you have to submit form many times before you will be able to submit it for sure.

Default behaviour of validation on submit for web (all fields are required):
Screenshot 2022-08-19 at 21.07.02

Default behaviour of validation on submit for api (all fields are required):
Screenshot 2022-08-19 at 21.08.49
we filled name and are ready to try submit again:
Screenshot 2022-08-19 at 21.09.36
we’re ended up with another error and again didn’t submit form (inconsistent UX).

I know validation of api part is in general more complex and it’s the most important validation to do and validation for web should be just addition to prevent api being called for obvious scenarios. But because of such differences I feel like it’s to easy to end up in situation where:

  • web and api validation definitions are incompatible and e.g. we didn’t allow submit some field on client side because our custom validation for client is more strict then validation of the service and vice versa,
  • we cannot guarantee consistent validation experience for the user

My question is does it always need to be done different for web and api? Is there any way to better deal with it? Are there any plans to improve and make validation more unified?

1 Like

Some time passed and I forgot about my question here. However, in the meantime, I think I have found the solution that I have been looking for.

There is a library called zod that allows you to define schemas. These schemas can be used to validate data on both the frontend and the backend to unify both worlds.

2 Likes

Hey darekdesu :slight_smile: I am glad you reported back!

I saw a video on zod and react-hook-form earlier this week! They used this GitHub - react-hook-form/resolvers: 📋 Validation resolvers: Yup, Zod, AJV, Joi, Superstruct, Vest, class-validator, io-ts, typanion, Ajv and nope. for integration with react-hook-form. The schema validation approach looks so simple. You said you think you have found the solution - I will be interested to hear if it does work like you are hoping.