以前の記事「APIが複数のパラメータ構造を持つ場合の対処法」では、APIが異なるパラメータ構造を必要とする場合、ApidogでoneOf、anyOf、またはallOfを使用してそれらを定義できることを説明しました。
これらのスキーマコンポジションを使用してパラメータ構造を設定し、パラメータにデータ型を識別するフィールドが含まれている場合、OpenAPI仕様のdiscriminator機能を使用することで、スキーマをより直感的に区別し、ドキュメントをさらに明確にすることができます。
Discriminatorとは?
OpenAPIにおいて、discriminatorの役割は、オブジェクト指向プログラミングにおける「ポリモーフィズム(多態性)」を実装することです。
簡単に言えば、共有プロパティとその一意な値を使用して、oneOfまたはanyOfリスト内のどの特定のスキーマを使用すべきかを明確に示します。
例えば、ペットショップでは、ペットを記述するためのスキーマを使用する必要があります。(そして、猫と犬は異なるプロパティを持っています。)
犬のスキーマは次のとおりです。
{
"name": "Hotdog",
"age": 3,
"weight": 25.5,
"petType": "dog",
"breed": "Golden Retriever",
"isVaccinated": true,
"walkingSchedule": "Morning and Evening",
"favoriteToys": ["Frisbee", "Tennis Ball"],
"trainingLevel": "Intermediate"
}猫のスキーマは次のとおりです。
{
"name": "Meow",
"age": 2,
"weight": 4.2,
"petType": "cat",
"isVaccinated": true,
"isIndoor": true,
"litterBoxType": "Enclosed",
"scratchingPostHeight": 120,
"favoriteSleepingSpot": "Balcony"
}ご覧のとおり、両方のスキーマにはpetType、name、ageなどの共通フィールドがありますが、犬にはbreed、walkingScheduleなどの特定のフィールドがあり、猫にはisIndoor、litterBoxTypeなどの特定のフィールドがあります。
APIドキュメントを設計する際に、これらのスキーマを定義するためにoneOfのみを使用した場合、ドキュメントは技術的にはdogスキーマとcatスキーマを区別できます。しかし、各型の対応関係はあまり明確ではありません。読者は2つのスキーマタブを切り替えて比較する必要があり、パラメータが多い場合には混乱を招きます。

discriminatorを追加することで、ドキュメントにはドロップダウンメニューが表示され、読者はpetTypeの値(dogまたはcat)を選択できます。選択すると、ページは関連するフィールドを持つ正しいスキーマを自動的に表示します。これにより、複数のタブを比較する必要がなくなり、各スキーマ間の違いがはるかに明確になります。

discriminatorは通常、oneOfまたはanyOfと一緒に使用されます。oneOfは可能なオブジェクトスキーマを定義し、discriminatorは選択されたタイプに基づいてどのスキーマを適用するかをパーサーに伝えます。
これにより、複雑なオブジェクトがより明確になり、ドキュメントのレンダリングやコード生成時にツールがタイプを自動的に区別するのに役立ちます。
discriminatorの設定プロパティ
discriminatorには2つの主要なプロパティが含まれています。
- propertyName: 上記の例の
petTypeのように、タイプを区別するために使用されるフィールド名を指定します。 - mapping: フィールド値と特定のスキーマ間のマッピング関係を定義します。例えば、
"dog"が犬のスキーマに対応し、"cat"が猫のスキーマに対応します。
OpenAPIでの設定例:
discriminator:
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'ApidogでのDiscriminatorの設定
Apidogは、discriminatorを2つの方法で設定することをサポートしています。
- GUI + JSON Schema
- OpenAPI仕様を直接インポートする
方法1:GUI + JSON Schema
まず、DogやCatなどのスキーマをApidogで作成します。

これらのスキーマを使用したいエンドポイントを開き、リクエストまたはレスポンスボディエディタに移動します。
スキーマコンポジションとして定義したいフィールドを選択し、Advanced Settings → Schema Compositions → oneOfを選択します。

oneOfで、DogやCatなど、必要なスキーマを参照します。

これで、oneOfを通じて複数の可能なスキーマを定義しました。次に、これらのスキーマを区別する方法を指定するためにdiscriminatorを追加する必要があります。JSON Schemaをクリックしてコードモードに切り替えます。

適切な場所(oneOfと同じ階層)にdiscriminator設定を追加します。例えば、次のようになります。
"discriminator": {
"propertyName": "petType",
"mapping": {
"dog": "#/definitions/190704823",
"cat": "#/definitions/190704706"
}
}mapping内の値(例:#/definitions/190704823)は、Apidogがスキーマ用に内部で生成する一意のIDです。各スキーマに対応するdefinitionsパスは、JSON Schema設定パネルで確認できます。

設定が完了したら保存します。APIドキュメントでは、petTypeフィールドの値に基づいてオブジェクトタイプをインテリジェントに切り替えることができます。

方法2:OpenAPI仕様を直接インポートする
これはより標準的なアプローチであり、「デザインファースト」のワークフローに慣れているチームに特に適しています。
discriminatorを含んだOpenAPI仕様を作成し、それをApidogにインポートします。
例えば、OpenAPI仕様におけるdiscriminatorの定義は次のとおりです。
Pet:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
discriminator:
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'この定義は明確に以下のことを示しています。
oneOfを通じて、オブジェクトがDogまたはCatタイプである可能性を指定します。discriminatorを通じて、petTypeフィールドの値に基づいて特定のタイプを決定することを指定します。mappingを通じて、"dog"がDogスキーマに対応し、"cat"がCatスキーマに対応することを明確に指定します。
完全なOpenAPI仕様は次のとおりです。
openapi: 3.0.3
info:
title: Pet Shop API
version: 1.0.0
components:
schemas:
Dog:
type: object
properties:
petType:
type: string
enum: [dog]
name:
type: string
age:
type: integer
weight:
type: number
breed:
type: string
isVaccinated:
type: boolean
walkingSchedule:
type: string
favoriteToys:
type: array
items:
type: string
trainingLevel:
type: string
required:
- petType
- name
- age
Cat:
type: object
properties:
petType:
type: string
enum: [cat]
name:
type: string
age:
type: integer
weight:
type: number
isVaccinated:
type: boolean
isIndoor:
type: boolean
litterBoxType:
type: string
scratchingPostHeight:
type: integer
favoriteSleepingSpot:
type: string
required:
- petType
- name
- age
Pet:
oneOf:
- $ref: '#/components/schemas/Dog'
- $ref: '#/components/schemas/Cat'
discriminator:
propertyName: petType
mapping:
dog: '#/components/schemas/Dog'
cat: '#/components/schemas/Cat'
paths:
/pets:
get:
summary: Get pet information
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'OpenAPI仕様が完成したら、Apidogのimport機能を使用します。Apidogはすべての仕様を解析し、対応するスキーマとエンドポイントを自動的に作成し、discriminator設定を正しく認識します(ここではパラメータ値を固定するためにenumが追加されています)。

よくある質問
1. Discriminatorはいつ使用すべきですか?
discriminatorは、エンドポイントにすでにスキーマを識別するフィールドが含まれている場合にのみ使用すべきです。上記の例では、API設計にpetTypeフィールドが存在し、ペットの種類を区別するために使用されています。
discriminatorは、そのフィールドの値に基づいて正しいスキーマを選択する方法をツールに伝えるだけです。
エンドポイントにそのような型識別フィールドが含まれていない場合、discriminatorは適切ではありません。その場合はoneOfのみで十分です。
また、スキーマがシンプルであるか、バリエーションが少ない場合は、そもそもdiscriminatorは必要ないかもしれません。
2. DiscriminatorはoneOfと一緒に使用する必要がありますか?
はい。discriminatorはoneOf、anyOf、またはallOfと一緒に使用する必要があります。それ自体でスキーマを定義することはできず、複数の可能なスキーマを区別する方法を説明するだけです。
結論
discriminatorは、oneOf/anyOf/allOfのユーザーエクスペリエンスを向上させるために使用されるOpenAPI仕様のオプション機能です。
エンドポイントの仕様にすでにタイプを識別するために使用されるフィールドが含まれている場合、Apidogでdiscriminatorを設定することで、APIドキュメントをより明確でインテリジェントにすることができます。
もちろん、設定が面倒だと感じる場合や、スキーマが比較的シンプルな場合は、oneOfのようなスキーマコンポジションのみを完全に利用することも可能です。
