JSON Schemaとreact-jsonschema-form


社内勉強会用資料。社内ツールでJSON Schemaとreact-jsonschema-formを利用しているので、それについての紹介です。

JSON Schema

JSON Schema

JSONの構造を定義するJSON。

例えば、下記のようなユーザを表すJSONがあるとする。

{
  "id": "00000000-0000-0000-0000-000000000001",
  "name": "Taro YAMADA",
  "age": 30
}
  • idはUUIDで、必須項目
  • nameは英字のみで、必須項目
  • ageは0以上の整数で、任意項目

こういう条件だった場合、JSON Schemaで下記のように定義できる。(あくまで一例だけど)

{
  "title": "ユーザー",
  "type": "object",
  "properties": {
    "id": {
      "title": "ID",
      "type": "string",
      "pattern": "^[0-9a-zA-Z]{8}(-[0-9a-zA-Z]{4}){3}-[0-9a-zA-Z]{12}$"
    },
    "name": {
      "title": "ユーザー名",
      "type": "string",
      "pattern": "^[\\sa-zA-Z]+$"
    },
    "age": {
      "title": "年齢",
      "type": "integer",
      "minimum": 0
    }
  },
  "required": [ "id", "name" ]
}

他にも色々と出来るけど、今回は割愛します。一番最初に貼ったリンクで仕様を読むか、下記のドキュメントが分かりやすかったので、そちらで勉強してください。

Understanding JSON Schema — Understanding JSON Schema 1.0 documentation

react-jsonschema-form

mozilla-services/react-jsonschema-form: A React component for building Web forms from JSONSchema.

react-json-schema-formは、JSON Schemaからフォームを生成してくれるReact Component。

Github Pagesにデモページがあるので、試しに先程のJSON Schemaを入れてみると下記のようなフォームが生成される。

使い方

Formコンポーネントに、下記のようなpropsを渡せば、最低限動作する。その他のpropsについては後述する。

  • schema ... JSON Schema
  • formData ... JSON
  • onChange ... 変更された時に呼ばれるハンドラ
  • onSubmit ... Submitボタンを押した時に呼ばれるハンドラ
import React from 'react';
import ReactDOM from 'react-dom';
import Form from 'react-jsonschema-form';

const schema = { ... };
const formData = {};

function handleChange({ formData }) {
  // 入力されたデータ
  console.log(formData);
}

function handleSubmit({ formData }) {
  // 入力されたデータ
  console.log(formData);
}

ReactDOM.render(
  <Form
    schema={schema}
    formData={formData}
    onChange={handleChange}
    onSubmit={handleSubmit}
  />,
  document.getElementById('app')
);

カスタマイズ

react-jsonschema-formは、カスタマイズがしやすいのが魅力だと思う。カスタマイズ方法を軽く紹介する。

uiSchema

propsにuiSchemaを渡すと、UI周りのカスタマイズが可能。

  • フィールド名、placeholderなどの変更
  • デフォルトの<input>要素の変更
  • class属性の変更

などなど、いろいろできる。わかりやすいやつを一部を紹介。

例1)helpTextの追加
<Form
  schema={{ ...さっきのJSON Schema }}
  uiSchema={{
    "name": {
      "ui:help": "半角英字、スペースのみ"
    }
  }}
/>

こうすると、

こうなる。

例2)placeholder


<Form
  schema={{ ...さっきのJSON Schema }}
  uiSchema={{
    "name": {
      "ui:placeholder": "半角英字、スペースのみ"
    }
  }}
/>

こうすると、

こうなる。(エラー起きちゃってるけど)

カスタムField

例えば、JSON Schema上は文字列でURLだが、ファイルアップロードするUIを表示したい場合、独自のFiledを表示することができる。

// JSON的にはURLが欲しい
const schema = {
  type: "string",
  format: "uri"
};

// AssetFieldコンポーネントを`asset`という名前で登録する
const customFields = {
  asset: AssetField,
};

// FieldにAssetFieldコンポーネントを使う
const uiSchema = {
  'ui:field': 'asset'
};

// fieldsに渡す
<Form schema={schema} uiSchema={uiSchema} fields={customFields} />

AssetFieldでは、下記のようにpropsで渡ってくるonChangeに値を渡して上げればOK。

import React, { Component, PropTypes } from 'react';
import uploadFile from './uploadFile';

class AssetField extends Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    // ファイルをサーバにアップロードして
    // URLを取得するような関数
    uploadFile(e.target.files[0]).then(url => {
      // onChangeで上げる値は、
      // JSON Schema通りの値じゃないと
      // validationでエラーになってしまう
      this.props.onChange(url);
    });
  }

  render() {
    const { required, disabled } = this.props;

    // ファイルアップロードを表示
    return (
      <input
        type="file"
        className="form-control"
        required={required}
        disabled={disabled}
        onChange={this.handleChange}
      />
    );
  }
}

export default AssetField;

おわり

とりあえず、こういうのあるよという紹介。JSON Schemaもreact-jsonschema-formももっと紹介したい機能があるので、またノウハウを貯めて書きたい