Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use JsonSchema for real-time client-side validation?

I'm evaluating using JSON Schema for validating form data.

I can use it to validate my form data when you click submit using AJV and then check it again on the server using a PHP implementation of JSON Schema.

That part sounds great, but I'm trying to figure out how I would use it for real-time validations -- i.e., validation as you're filling out the form/typing.

Specifically, I can run the entire validator on every keystroke, but it seems expensive to validate the whole form when only one input has changed. In particular, any AJAX-based validations (such as a username uniqueness check) would fire too frequently.

Has anyone used JsonSchema for this purpose? Is it feasible? How would I fine-tune AJV or another JsonSchema implementation to only run the validators that are necessary on input?

like image 541
mpen Avatar asked Oct 29 '22 00:10

mpen


1 Answers

Integrating this with the client will depend heavily on what you're using on the client side. I'm working on a project using this with dynamically created forms in Angular 2+ and AJV and it is working really well.

It will also depend on how much of JSON Schema you're using. For example, I want my forms to be able to use $data references so that validity of one input can depend on the value of other inputs. This basically means I have to validate on any change in the form since there's not an effective way to tell what value is the target of a $data reference.

Also, if there's any potential for your model data to change outside of the user interacting with the form (e.g., new data being pulled from the server from other users, etc.) it is much more resilient to validate the schema and model in its entirety.

In general even on my more complicated forms with up to 30-40 input values ajv takes less than 10ms to validate the entire form including a function of my own to match ajv's errors to my inputs for display. So I wouldn't worry about the performance hit.

Edit: As for the async validators adding a debounce of some sort will depend on what you're using client side, but shouldn't be too hard and AJV's documentation is really complete.

Edit: Here's the loop I have the errors go through to match them and clean them up a little (most of AJV's errors are user readable, but a few like pattern matching need some help rather than spitting out a regex at the user):

errs.forEach((err) => {
  // Is this a value that is being matched to another input?
  if (err.dataPath === dataPath && err.keyword === 'const' && err.schema.$data) {
    return messages.push('Does not match')
  }

  // Don't show regex to people.
  else if (err.dataPath === dataPath && err.keyword === 'pattern') {
    return messages.push('Not valid format')
  }

  // Is the keyword 'required' and the parentPath is a match and the property is matched to err.params.missingProperty
  else if (err.keyword === 'required' && err.dataPath === parentPath && err.params.missingProperty === propertyName) {
    return messages.push('Required')
  }

  // Is the dataPath a match and no other special criteria apply
  else if (err.dataPath === dataPath) {
    // Cap first letter
    return messages.push(err.message.charAt(0).toUpperCase() + err.message.slice(1))
  }
})
like image 190
Roy Reiss Avatar answered Nov 15 '22 05:11

Roy Reiss