読者です 読者をやめる 読者になる 読者になる

yoskhdia’s diary

DDDとかプログラミングとかアーキテクチャとか雑多に

Swagger(OpenAPI) Specification 2.0におけるOptionalなプロパティに値が無い場合の仕様を調べた話

Swagger(OpenAPI) Specification 2.0(以下、OAS)を最近触り始めているのですが、Optionalなプロパティに値が無いときのJSONは何が許されるのかを調べたエントリです。

JSON Schema Specificationの requiredキーワードtype: null について確認しました。 OAS2.0ではModelはSchema Objectとして定義されており、これは JSON Schema Specification Draft 4 となっています。 OASでは、Schema Objectのrequiredキーワードおよびnullについて特に言及はありません。 そのため、JSON Schemaの仕様*1に準拠すると解釈し、これを調査しました。*2

TL;DR

  • requiredキーワードに指定されていない(Optional)プロパティは、API間でやり取りするJSONからそのプロパティを省略できる。
  • Optionalなプロパティを空でセットするには、そのtypeにとって妥当なデフォルト値をセットする方がJSON Schema仕様との齟齬がなさそう。

JSON Schemaでのrequiredキーワードの扱い

requiredキーワードの仕様を見ると、

An object instance is valid against this keyword if its property set contains all elements in this keyword’s array value.

となっており、requiredキーワードに指定したプロパティが全て、オブジェクトのインスタンスにセットされているかがバリデーションの対象となっています。 requiredキーワードはプロパティが存在するかに関心があり、その値が何である必要があるかまでは定義していません。

JSON Schemaでのnullの扱い

nullの扱い(およびtypeの定義)については、Swaggerと大きな差があります。 まず、JSON Schemaにおいては、nullも1つのtypeとして定義されています。 そのため、例えばstringまたはnullを受け取る可能性のあるパラメータは

{
  type: ["string", "null"]
}

と定義する必要があります。 しかし、Swaggerでは、このようなMulti-typeは定義することが許されていません。 このIssueでも2年に渡って(!)議論されていましたが、OAS3.0にて nullable キーワードが足されることで決着がついたようです。

バリデーション動作

http://www.jsonschemavalidator.net/ にて、JSON Schemaのバリデーションをテストできます。 requiredキーワードとnullについて、いくつか確認してみました。

Schema定義

{
  description: "商品情報",
  type: "object",
  required: ["sku"],
  properties: {
    sku: {
      type: "string",
      description: "商品を特定するための識別子"
    },
    name: {
      type: "string",
      description: "商品名"
    }
  }
}

試行

{
  name: "foo"
}

👉 Required properties are missing from object: sku.とエラー。

{
  sku: ""
}

👉 問題なし。

{
  sku: null
}

👉 Invalid type. Expected String but got Null.とエラー。

まとめ

以上のことから、2つのことが言えると思います。

  • requiredキーワードに指定されていない(Optional)プロパティは、API間でやり取りするJSONからそのプロパティを省略できる。
  • Optionalなプロパティを空でセットするには、そのtypeにとって妥当なデフォルト値をセットする方がJSON Schema仕様との齟齬がなさそう。

typeにとって妥当なデフォルト値がJSON Schema Specificationで定義されているのかも見てみましたが、いくつかのキーワードで値の指定が無い場合の振る舞いが定義されているのみで、プリミティブなtypeのデフォルト値については特に見当たりませんでした。何をデフォルト値とするかはケースバイケースであるので、defaultキーワードを指定することで、これを明示する方が好ましいのかもしれません。

全てのOptionalなプロパティにdefaultを指定することが面倒であれば、そのプロパティをセットしないという選択肢もあります。 また、ライブラリによっては、それがデフォルトとなっているものもあります。*3 サーバサイドとクライアントサイドで、使用する言語やライブラリが異なることは多々ありますので、予めOptionalなプロパティをどう扱うのかを明確に取り決めておくことが肝要でしょう。

*1:本エントリではJSON Schema Specification Draft 4を対象にしています。

*2:解釈の誤りなどあればコメントやTwitterなどでご指摘ください。

*3:play-jsonなど