Help us understand the problem. What is going on with this article?

JSON Schemaと友達になる為の記事

こちらの記事はSpeee Advent Calendar 2016の17日目の記事です。

前日の記事は@yhattPostCSS は ポストCSS の夢を見るか?です。

今回は新卒エンジニアである私がJSON Schemaの入門的な記事を書かせていただきます。

はじめに

そもそも JSON Schema とは何やねん! となる方も多いと思うので簡単に解説しておくと、
json-schema.orgによって開発されているJSON objectを記述したり検証したりするための設計書のようなものです。

この JSON Schema ですが,

  • JSON Schema Core
  • JSON Schema Validation
  • JSON Hyper-Schema

の3つの仕様があります。
今回は JSON Schema Core と JSON Hyper-Schema を使って一つのAPIの仕様を定義していきたいと思います。

本記事ではJSON Schemaの draft v4 を使用します。

基本機能編(JSON Schema Core)

STEP 1

まずは JSON Schema Core の基本的な書き方と仕様の説明をします。

下記のようなサンタさん用の配達リスト(JSON)を返すAPIがあるとします。

{
  "children": [
    {
      "id": 1,
      "name": "tarou",
      "address": "東京都港区hogehoge",
      " presents": [
        {
          "id": 101,
          "name": "2DS",
          "price": 9,998
        },
        {
          "id": 302,
          "name": "ポケモン",
          "price": 4,298
        }
      ]
    },
    {
      "id": 2,
      "name": "hanako",
      "address": "東京都渋谷区hogehoge",
      " presents": [
        {
          "id": 534,
          "name": "ラブあみDXセット",
          "price": 2,900
        },
      ]
    }
  ]
}

このJSONをJSON Schema Coreにのっとって定義すると

{
  "type": "object",
  "properties": {
    "children": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "description": "子供のID",
            "type": "integer"
          },
          "name": {
            "description": "子供の名前",
            "type": "string"
          },
          "address": {
            "description": "子供の住所",
            "type": "string"
          },
          "presents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "description": "プレゼントID",
                  "type": "integer"
                },
                "name": {
                  "description": "プレゼント名",
                  "type": "string"
                },
                "price": {
                  "description": "プレゼントの価格",
                  "type": "integer"
                }
              }
            }
          }
        }
      }
    }
  }
}

こんな感じになります。
JSONの構造に合わせて型を定義しただけの状態です。
非常に読みづらいですが我慢してください。
ココで使われているものの細かい説明していきます。

  • type:

読んで字のごとし、型が何かを定義する部分です。
nullの可能性がある時は ["string", "null"] と定義します。

  • properties:

こいつも読んで字のごとし、プロパティを定義する部分。

  • items:

中身が配列になるときはこいつを使います。

  • description:

説明文

ここまで出てきたものは誰がどう見ても、「まぁそうだろう」という感じのものばかりです。
簡単ですね。

STEP 2

この読みづらいJSONの中には

  • childオブジェクト
  • presentオブジェクト
  • その2つを持ったchildrenオブジェクト

が存在しています。
なので childオブジェクト と presentオブジェクト 切り出してみようと思います。

{
  "$schema": "http://json-schema.org/draft-04/schema",
  "definitions": {
    "child": {
      "definitions": {
        "id": {
          "description": "子供のID",
          "type": "integer"
        },
        "name": {
          "description": "子供の名前",
          "type": "string"
        },
        "address": {
          "description": "プロモーションコード",
          "type": "string"
        }
      }
    },
    "present": {
      "properties": {
        "id": {
          "description": "プロモーションコード",
          "type": "integer"
        },
        "name": {
          "description": "プロモーションコード",
          "type": "string"
        },
        "price": {
          "description": "プロモーションコード",
          "type": "integer"
        }
      }
    }
  },
  "type": "object",
  "properties": {
    "children": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/definitions/child/definitions/id"
          },
          "name": {
            "$ref": "#/definitions/child/definitions/name"
          },
          "address": {
            "$ref": "#/definitions/child/definitions/address"
          },
          "presents": {
            "type": "array",
            "items": {
              "$ref": "#/definitions/present"
            }
          }
        }
      }
    }
  }
}

結構スッキリしましたね。
ここで新たに出てきたプロパティについて説明します.

おまじないです。これでこのJSONではjson-schema.orgのdraft-04を使用します! という宣言です。

  • definitions

スキーマのテンプレートを定義しておく場所です。
あくまでテンプレートなのでスキーマではないので注意が必要です。

  • "$ref"

definitionsで定義したテンプレートを参照します。

ここで出てきた3つは必ず覚えておくといいでしょう。
たくさん使うことになります。

API定義編(JSON Hyper-Schema)

ここではサンタさん用の配達リスト(JSON)を返すAPIのエンドポイントなどを JSON Hyper-Schema に則って定義していこうと思います。

JSON Hyper-Schemaのメインはlinksというプロパティです。こいつのためにあるものと言っても過言ではないでしょう。

{
  "$schema": "http://json-schema.org/draft-04/schema",
  "definitions": {
    "child": {
      "definitions": {
        "id": {
          "description": "子供のID",
          "type": "integer"
        },
        "name": {
          "description": "子供の名前",
          "type": "string"
        },
        "address": {
          "description": "プロモーションコード",
          "type": "string"
        }
      }
    },
    "present": {
      "properties": {
        "id": {
          "description": "プロモーションコード",
          "type": "integer"
        },
        "name": {
          "description": "プロモーションコード",
          "type": "string"
        },
        "price": {
          "description": "プロモーションコード",
          "type": "integer"
        }
      }
    },
    "children":{

    }
  },
  "type": "object",
  "properties": {
    "children": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "$ref": "#/definitions/child/definitions/id"
          },
          "name": {
            "$ref": "#/definitions/child/definitions/name"
          },
          "address": {
            "$ref": "#/definitions/child/definitions/address"
          },
          "presents": {
            "type": "array",
            "items": {
              "$ref": "#/definitions/present"
            }
          }
        }
      }
    }
  },
"links": [
    {
      "href": "http://hogehoge/api/hogehoge",
      "method": "GET",
      "rel": "self"
    }
  ]
}

これが一番簡単な形です。

  • href:

APIのURLを指定する箇所

  • rel:

スキーマが表すインスタンスと、リンク先との関係性を表すもので色々と指定できます。
1.self
インスタンス自身のURLを指定するもの。
2.create
新しいインスタンスを作成するリンクを表します。

 などなど

  • method:

GETとかPOSTとかPATCHとか

一番簡単な状態だとpropertiesで指定されている値を返します。
他の値を返したい場合は下記のような感じになります。

"links": [
    {
      http://hogehoge/api/hogehoge
      "method": "GET",
      "rel": "self",
      "targetSchema": {
        "properties": {
          "プロパティー名": {
            "$ref": "#/definitions/hogehoge"
          }
        },
        "type": [
          "object"
        ]
      }
    }
  ]

targetSchema をつけてあげるとそのAPIで返す値を定義できます。

受け取る値の定義は

"links": [
    {
      http://hogehoge/api/hogehoge
      "method": "POST",
      "rel": "create",
      "schema": {
        "properties": {
          "プロパティー名": {
            "$ref": "#/definitions/hogehoge"
          }
        },
        "type": [
          "object"
        ]
      }
    }
  ]

上記のようにschemaをつけてあげると定義できます。
簡単ですね。

おしまい

今回ざっくりJSON Schemaの入門的記事を書きました。
私が紹介したプロパティはほんの一部です。他にも沢山のプロパティが定義されています。
興味が出た方はぜひjson-schema.orgを見ていただければ幸いです。

本記事で紹介しなかったJSON Schema Validationについては機会があれば後日記事にしようと思います。

私自身、業務で自社カスタムしたJSON Schema定義を使用して書いている間違いがあるかもしれません。
正しく理解できておらず間違いが書いてあった場合はコメント等で指摘いただけるとうれしいです。

つたない文章に最後までお付き合い頂きありがとうございました。

arumi8go
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした