Few questions about service validation errors and forms

Hi to all.
I’m playing around with RW Forms based on example from tutorial and I’m bit confused with service validation. To be precise, in Chapter 5, ‘Saving data’ part there is an example how to validate input on service level that shows how to validate multiple input fields:

  validate(input.email, 'email', { email: true })
  validate(input.name, 'name', {
    inclusion: ['Audi', 'BMW', 'Ferrari', 'Lexus', 'Tesla'],
  })

However, I noticed that, with code from tutorial, If I try to break more than one field validation (e.g. providing wrong e-mail address and wrong car make) I got only one error (in fact, result of first validation violation). What I realised is that validate method throws error so, first instance will break whole procedure. I don’t know is this by design or I misunderstood something but, would it be good to validate multiple fields and provide whole set of errors at once back to UI (to user). As mentioned on same page, would it be nice to have all errors on same place instead of pushing user to fix one-by-one? Is there any example how to return more than one error?

Also, regarding GraphQL error beeing returned to form, I’m curios would, in case of multiple validation, we would have single ‘BAD_USER_INPUT’ errors and then multiple messages in extensions.properties.messages section (one per each field) or it should be multiple graphQLErrors, one per each validation?

image

Also, I’m curious about ‘magic’ that RW forms is performing to convert this GQL error ‘mess’ into nicely formatted messages for FormError and field errors? Is it something that is bounded to RW controls (e.g. that controls itself filter out interesting data from messages) or it can be used as a helper function to be used with other form libraries (e.g. to get object containing just field error messages and use it further on). In my case,

Sorry in advance if all of these are noob questions but, I would appreciate any help.

1 Like

Hello! Currently Service Validations are “short circuit” errors in that they stop processing as soon as there’s any one single error and just return that one. We could look into running them all and bundling up the errors into one response. Off the top of my head I think it would only bundle up those validation errors—if there were errors later in the process (like if Prisma itself errored) those would still be separate (but maybe it’s possible to bundle those up as well, we’d have to experiment…)

You can see the code for parsing these errors here: redwood/FormError.tsx at main · redwoodjs/redwood · GitHub

It’s complicated by the fact that there are two different kinds of errors, GraphQL and Network. As far as reuse, right now you can see it’s tied into displaying the message at the top of the page in the <FormError> component, but it could probably be refactored into two separate modules: parsing and collecting errors, and display. Is that something you’d be interesting in contributing? We love folks opening PRs! We just ask that you open an RFC Issue first so people can give feedback and discuss.

2 Likes

Also, the Core Team is thinking of changing up how GraphQL errors are included in a response (ie, not in the extensions as you noted above) as part of the data itself. This is done via “union types” and Jamie Barton has an excellent video here that describes the approach:

1 Like

I don’t know is there any ‘GraphQL standard’ about how to return multiple errors but I (think so) agree with you. From my point of view, any number of validation errors can be combined together into single ‘BAD_USER_INPUT’ error (at the end, it is a single problem, caused by multiple smaller issues that all needs to be resolved to resolve ‘base’ problem/error). Any other errors that can occur (e.g. NETWORK_ERROR) should be standalone errors.
I’ll try to show with mock example:

{
graphQlErrors: [
 {
   code: "BAD_USER_INPUT",
   message: "Invalid user input",
   properties: {
     messages: [
          field1: "Validation error for field 1",
          field2: "Validation error for field 2"
          field3: "Validation error for field 3"
     ],
     ...
},
{
   code: "NETWORK_ERROR",
   message: "Some network error message",
}
]}

But now, when I look into this proposal, I’m wondering do we need to ‘lock’ ourselves into ‘one error per field’ logic. There could be some validation rules containing relation of multiple fields or anything other that can not be mapped into single field…

I will try to write (at least) RFC to discuss further on, as soon as I get some time to watch video that David sent.

3 Likes

On the client, you would expect to see data validation errors based on the rules applied by js and html standard form attributes, and these all show up if you submit the form without meeting the requirements. Remix punts to this behavior for their client validation logic from what I remember. Not sure how validation logic is done under the hood on RW just yet. It’s like a mix of schema checks if it gets to that point and some app logic pre-validating I guess? I really want to run the form generation to create validation rules in the markup and decide which fields to display, the backend api validation and the automated testing to a spec like JSON Spec or something so it’s all operating off the same ruleset and customization time is minimized. Too much of my life has been spent redeclaring the same validation/schema sanity check that exists on the database in the client and the apis. If you guys come up with something novel, please let it be a solution to the tedium of writing boilerplate validation code in 3-4 places. The world will thank you.

I hear you! Right now you declare datatypes/requirements in your Prisma schema and GraphQL SDL no matter what. You can optionally add it to your client-side forms and additionally on your services.

We can generate the SDL ones for your based on your Prisma model, but that’s about as far as we go. I wonder what it could look like to tell your forms that you want client-side validation, and here’s where to automatically get it from. Maybe we can generate some kind of zod schema based on your Prisma model and use that for both form and service validation?