react-jsonschema-formのバリデーションをカスタマイズしてみる

これは「react-jsonschema-formのカレンダー | Advent Calendar 2023 - Qiita」の10日目の記事です。

この記事では、react-jsonschema-form (RJSF) の公式ドキュメントでバリデーションまわりを見てみます。
Validation | react-jsonschema-form

その後、RJSFのバリデーションをカスタマイズしてみます。

 
目次

 

環境

  • react-jsonschema-form 5.15.0
  • React 18.2.0
  • React Router 6.20.1

 

RJSFのバリデーションについて

RJSFのバリデーションとしては

  • HTMLのバリデーション
  • Ajvの8系を使ったバリデーション

が用意されています。

また、要望に応じて、それらのバリデーションをカスタマイズすることもできます。

 
今回は、上記2つのバリデーションについて、もう少し見ていきます。

 

HTMLのバリデーションについて

HTMLのバリデーションとは、以下のMDNにあるようなHTMLのフォーム検証となります。

 
JSON Schemaにて typeformat を指定することにより、RJSFが適切なHTMLタグを生成してHTMLのバリデーションが行われます。

なお、HTMLのバリデーションは無効化することもできます。これは後で見ていきます。
HTML5 Validation | Validation | react-jsonschema-form

 

Ajvの8系を使ったバリデーションについて

RJSFでは、 Ajv ライブラリを使って JSON Schema に対するバリデーションを行っています。

Ajv の公式サイトに Ajv JSON schema validator とある通り、JSON Schema のバリデーションを行うライブラリです。
Ajv JSON schema validator

 
AjvがサポートしているJSON Schemaのバージョンは以下に記載があります。
JSON Schema | Ajv JSON schema validator

Ajvのdefault exportでは draft 7 が使われるようです。

 
簡単ではありますがRJSFのバリデーションの概要を見ました。

次は、RJSFのバリデーションを見ていきます。

 

HTMLのバリデーションを無効にする

HTMLのバリデーションを無効にするには、Fomのprops noHtml5Validatetrue にします。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#html5-validation

 
まずはHTMLのバリデーションが有効な時の状態です。

JSON Schemaで requred を指定しておきます。

import {RJSFSchema} from "@rjsf/utils";
import Form from "@rjsf/mui";
import validator from "@rjsf/validator-ajv8";

export const EnabledHtml5ValidationForm = () => {
  const schema: RJSFSchema = {
    title: "Enabled HTML5 Validation Form",
    type: "object",
    required: ["stringInput"],
    properties: {
      stringInput: {
        type: "string",
      }
    }
  }

  return (
    <div style={{width: '400px'}}>
      <Form
        schema={schema}
        validator={validator}
      />
    </div>
  )
}

 
動作を確認します。何も入力せずにsubmitすると、HTMLによるエラーが表示されます。

 
続いて、Formのpropsに noHtml5Validate を追加します。

<Form
  schema={schema}
  validator={validator}
  noHtml5Validate
/>

 
この状態で何も入力せずにsubmitすると、HTMLによるエラーではなく、RJSFによるエラーが表示されます。

 

リアルタイムバリデーション(ライブバリデーション)する

RJSFでリアルタイムバリデーション(ライブバリデーション)を行う場合、Formのprops liveValidate を使うことで実現できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#live-validation

実際にためしてみます。今回は

  • 入力欄は、最低3文字の入力が必要
  • Formに liveValidate を追加

とします。

import {RJSFSchema} from "@rjsf/utils";
import Form from "@rjsf/mui";
import validator from "@rjsf/validator-ajv8";

export const LiveValidationForm = () => {
  const schema: RJSFSchema = {
    title: "Live Validation Form",
    type: "object",
    required: [],
    properties: {
      stringInput: {
        type: "string",
        minLength: 3
      }
    }
  }

  // onSubmitの引数の説明は以下
  // https://rjsf-team.github.io/react-jsonschema-form/docs/api-reference/form-props#onsubmit
  const onSubmit = ({formData}, _event) => {
    console.log(formData)
  }

  return (
    <div style={{width: '400px'}}>
      <Form
        schema={schema}
        validator={validator}
        onSubmit={onSubmit}
        liveValidate
      />
    </div>
  )
}

 
動作を確認します。ab という2文字入力時点ではエラーが表示されています。

 
3文字目の c を入力すると、バリデーションエラーではなくなったため、エラーメッセージが非表示となりました。

 

バリデーションのカスタムルールを追加する

JSON Schemaに書くことである程度のバリデーションは実現できます。

ただ、もう少し詳しいバリデーションや複数項目を組み合わせた時のバリデーションを行いたいときもあります。

その場合は、バリデーションのカスタムルールを追加することで実現できます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#custom-validation-rules

 
今回は rangeFromrangeTo の2項目を追加し、 rangeFrom > rangeTo の場合にエラーとなるバリデーションを追加します。

まずはバリデーションルールの関数を用意します。関数のインタフェースは公式ドキュメントに従います。

const customValidate = (formData: FormData, errors: FormValidation<FormData>): FormValidation<FormData> => {
  console.log(formData)

  if (formData.rangeFrom > formData.rangeTo) {
    // rangeToはrequiredなバリデーションの後にここへ来るので、今回は `!` を使っておく
    errors.rangeTo!.addError("rangeTo must be greater than rangeFrom")
  }

  return errors
}

 
続いて、Formのprops customValidate にバリデーションルールの関数を渡します。

<Form
  schema={schema}
  validator={validator}
  customValidate={customValidate}
/>

 
動作を確認します。バリデーションエラーとなるような入力をすると、画面にメッセージが表示されました。

 
なお、integer型の項目に 3.4 を入れるなど、JSON Schemaのバリデーションエラーとなる値を入力した場合は、そのエラーも同時に表示されます。

 

バリデーションのエラーメッセージを変更する

RJSFではバリデーションエラーとなった時のメッセージが用意されています。

もし、エラーメッセージを変更したい場合にはカスタマイズできます。
https://rjsf-team.github.io/react-jsonschema-form/docs/usage/validation/#custom-error-messages

 
まず、エラーメッセージを変換する関数を用意します。

差し替えるerrorレコードであった場合に

  • message
    • デフォルトでは、入力項目の下に表示されるエラーメッセージ
  • stack
    • デフォルトでは、一番上の Errors に表示されるエラーメッセージ

などを差し替えます。

ちなみに、errorオブジェクトには以下のようなデータが渡されてきます。

{
    "name": "format",
    "property": ".stringInput",
    "message": "must match format \"email\"",
    "params": {
        "format": "email"
    },
    "stack": ".stringInput must match format \"email\"",
    "schemaPath": "#/properties/stringInput/format"
}

 
今回は、入力項目 stringInput のエラーが format であった場合に、エラーメッセージを差し替えるようにします。

const transformErrors = (errors: RJSFValidationError[], _uiSchema: typeof schema) => {
  console.log(errors)

  return errors.map((error) => {
    if (error.property === '.stringInput' && error.name === 'format') {
      error.message = 'My email error message'
      error.stack = 'Stack error message'
    }

    return error
  })
}

 
続いて、Formのprop transformErrors に関数を指定します。

なお、 email の場合HTMLバリデーションが実行されてしまうので、今回の動作確認ではHTMLバリデーションを無効化しておきます。

<Form
  schema={schema}
  validator={validator}
  transformErrors={transformErrors}
  noHtml5Validate
/>

 
動作を確認します。emailとして不適切な値を入力すると、差し替えたエラーメッセージが表示されました。

 

ソースコード

Githubにあげました。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023

今回のプルリクはこちら。
https://github.com/thinkAmi-sandbox/rjsf_advent_calendar_2023/pull/9