お仕事でPowerAutomateワークフローの構築・運用をする中でしばしばお世話になっているJSON Schema。直近その仕様を確認する機会があったので、その結果をご紹介。
PowerAutomateでは「JSONの解析」アクションでこのJSON Schemaを使用。ふつうは「サンプルから生成」機能で、既存のJSONを元に自動導出するはず。
ただサンプルはあくまでサンプル。実際にフローを実行してみると、サンプルベースのスキーマでは不十分で、自動導出されたスキーマに手を加えないとならないことも。
そうした時の参考になるかと。
JSON Schemaとは?
IETFという標準化団体のもとで標準化されているJSONデータの構造を定義するための言語。
構造定義によりJSONを用いたアプリケーション間のコミュニケーションの生産性・品質を向上させる。
AjaxやRESTfulAPIの普及とともにその必要性が生じ、近年ではシングルページアプリケーションのデファクト化やマイクロサービス化とともに重要度が上がっている状況。
Swagger(OpenAPI)でもJSON Schemaのサブセットが利用。
定義そのものがJSON形式で記述。
仕様には複数バージョンあり、スキーマ生成・解釈をする実装ごとにサポート状況に差がある点は要注意。
スキーマ例
次のようなJSONがあるとき、
{
  "productId": 1,
  "productName": "A green door",
  "price": 12.50,
  "tags": [ "home", "green" ]
}
そのスキーマは次のように表現される:
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://example.com/product.schema.json",
  "title": "Product",
  "description": "A product from Acme's catalog",
  "type": "object",
  "properties": {
    "productId": {
      "description": "The unique identifier for a product",
      "type": "integer"
    },
    "productName": {
      "description": "Name of the product",
      "type": "string"
    },
    "price": {
      "description": "The price of the product",
      "type": "number",
      "exclusiveMinimum": 0
    },
    "tags": {
      "description": "Tags for the product",
      "type": "array",
      "items": {
        "type": "string"
      },
      "minItems": 1,
      "uniqueItems": true
    }
  },
  "required": [ "productId", "productName", "price" ]
}
(参考ページより引用)
第1階層にはスキーマそのもののメタ情報($schema、$id、titleなど)と、ルートとなるデータ型(type)。
第2階層(propertiesのプロパティ)にはオブジェクトのプロパティの定義情報。プロパティのデータ型もまたobjectの場合は入れ子構造でプロパティの定義情報が記述される。
データ型+α の表現力
JSON SchemaはJSONの仕様に定められたJSONのデータ型について記述することはもちろん、それらが特定のJSONデータにおいてどのように構造化されているかを定義。
さらにJSON仕様だけでは表現できないごとにさまざまなデータの制約も表現できる。
例えば、
| 型 | 型固有のキーワード | 説明 | 
|---|---|---|
| array | items, minItems, maxItems, uniqueItems | 要素のスキーマ定義、要素数の制約、要素の一意性など | 
| number | minimum, maximum, exclusiveMinimum, exclusiveMaximum, multipleOf | 数値の範囲、倍数制限など | 
| object | required, properties, patternProperties, minProperties, maxProperties | 必須プロパティ、入れ子のプロパティ、正規表現によるプロパティマッチング、プロパティ数の制約など | 
| string | minLength, maxLength, pattern, format | 文字列長の制限、正規表現による制約、所定のフォーマットへの適合など | 
参考ページ
JSONらしい柔軟な構造定義
JSONの特性はそのシンプルさと柔軟性。後者はメリットにもデメリットにもなる。アプリケーション間でJSONデータのやり取りするとき「存在する想定でいたプロパティが存在しない」「プロパティの型が想定していたものではない」といった問題が生じうる。
JSON Schemaにはこの「柔軟性」を定義するための構文やキーワードも存在。
例えば、
| 構文・キーワード | 説明 | 
|---|---|
| "type": ["type1", "type2", ...] | いずれかのデータ型に該当する | 
| "anyOf": [{ ... }, ...] | サブスキーマのいずれかに該当する | 
| "not": {...} | サブスキーマに該当しない | 
| required | 指定したプロパティが必ず存在する | 
| dependentrequired | プロパティAが存在する場合、別のプロパティBやCも存在する | 
| "if": {...}, "then": {...},"else": {...}  | 条件として指定したサブスキーマにマッチする場合としない場合とで、それぞれ別のサブスキーマにマッチするかを検証 | 
nullもデータ型の1つである点に注意! null値を取りうるプロパティはそのことをきちんとスキーマに表現する必要がある。"type": "string"ではなく "type": ["string", "null"]でないといけないということ。
さらに高度な検証
ここまでざっと見てきた以外にも、条件付きのスキーマ検証の定義や、取りうる値を列挙型や定数として制約、日時・日付・時刻・Eメールといったフォーマットの定義など、さらに高度な検証の助けとなる仕様も存在する。
