Custom validators

Ensuring data entered conforms to your requirements

Formsort has many validators already built-in, such as restrictions on values entered into a number question, or ensuring text entered into an email field looks like an email.

When these don't suffice for your use case, you can define custom validators to define your own logic by which a responder's answers should be validated.

Answers can be validated using regular expressions, custom code, or via APIs.

Custom validators are only available in the Enterprise tier.

Defining custom validators

Custom validators are defined at the workspace level.

Validator metadata

The first step to defining a custom validator is to specify its metadata. These will be used when referring to the validator. It is also important to specify the Type of the answers that this validator pertains to, so that Formsort knows what answers can use it (it wouldn't make sense to use a number validator on object inputs, for example)

Defining rules

The rules of a custom validator are what the input answer value is evaluated against. To be considered valid, a value must match all of the input rules.

Rule severity

Each rule has an associated severity

Regular expression rules

Regular expressions are only available for string answer types.

Regular expressions either allow or disallow matching of an input string against a pattern.

As an example, if we wanted to validate a Twitter handle per the Twitter username rules, we can use the following regular expressions and flags to screen for a variety of conditions:

  1. Input: Must match Valid Pattern: ^[a-zA-Z0-9_]+$ Error message: "A username can only contain alphanumeric characters (letters A-Z, numbers 0-9) with the exception of underscores."

  2. Input: Must match Valid Pattern: ^.{1,15}$ Error message: Handles must be between 1 and 15 characters long.

  3. Input: Must not match Invalid Pattern: Twitter|Admin Case insensitive: Enabled Error message: The words "admin" or "twitter" cannot appear in your handle.

Rules 1 and 2 (and probably 3) can be collapsed into a single regular expression that checks for both, which would be ^[a-zA-Z0-9_]{1,15}$.

Splitting out rules is preferred, as it allows for more targeted error messages. We can warn users with a specific message when they have an invalid character OR their handle is too long, making it easier to see what's wrong with the input and correct it.

For more information on regular expressions, see MDN's Regular expression syntax cheat sheet or just google around for examples.

Custom code rules

Sometimes it's easier to just write a little code to validate some data. For this, we allow writing of custom code to validate values.

For example, the rules we created using the regular expressions above could be re-written as the following:

function myFunction(value: string): ValidatorResult | undefined { // readonly line
  if (value.match(/admin|twitter/i)) {
    return {
      severity: 'error',
      message: 'Handle cannot contain the words "admin" or "twitter"'
    }
  }
  if (value.match(/[^a-zA-Z0-9_]/)) {
    return {
      severity: 'error',
      message: 'A username can only contain alphanumeric characters (letters A-Z, numbers 0-9) with the exception of underscores.'
    }
  }
  if (value.length > 15) {
    return {
      severity: 'error',
      message: 'Usernames cannot be more than 15 characters long'
    }
  }
}

Custom code validators should return a ValidatorResult if they encounter a problem with the input value, which defines the severity and an optional message to show the responder.

return {
  severity: 'error',
  message: 'This is a bad input'
}

If there are no problems, then nothing needs to be returned.

Async custom code

Custom code rules can also be asynchronous, if Async is checked.

This allows you to do things like use fetch() and json()to retrieve data from elsewhere, using the await keyword in Typescript.

This is a hypothetical example, but let's imagine Twitter had a public API for checking whether a handle was already taken. We could verify it with the following custom code rule.

function myFunction(value: string): Promise<ValidatorResult | undefined> { // readonly line
  const res = await fetch('https://api.twitter.com/check-handle');
  const handleInfo = await res.json();
  if (handleInfo.taken) {
    return {
      severity: 'error',
      message: 'This handle has already been registered'
    }
  }
}

Testing validators

In the Test tab, it's possible to try out values and see the error or warning messages that would be shown for that input.

Testing out our Twitter handle validator, we can see that each of the rules is enforced separately:

We can also see that the rules are evaluated separately: putting a value that violates them all separately will create an exception for each:

Using custom validators in a flow

Once a custom validator is defined in the workspace, it will appear in the settings pane for questions that have the validator's type.

Validators are also available for selection from the answers editor, such as for External variables.

Updating custom validators

It's possible to update custom validators once they are used - but the flows using them will not be automatically re-deployed.

To figure out which flows need to be re-deployed once a validator is updated, from the validators page, choose Show usages.

From here, it's possible to see which flows are using the validator:

Deleting a custom validator

It's possible to delete a validator from the validators list. Flows using the deleted validator will continue to work, but it will not be available for addition to any new questions or answers.

Last updated