APIパラメータは、単一のエンドポイントが複数の異なるパラメータの組み合わせをサポートするなど、複雑な構造を持つことがよくあります。例えば、ログインエンドポイントは、ユーザー名とパスワードによる認証、メールアドレスとパスワードによる認証、または電話番号による認証コードをサポートする場合があります。支払いエンドポイントは、クレジットカード、WeChat Pay、Alipayなど、それぞれ異なるフィールドを必要とする様々な方法を提供できます。

従来のAPIドキュメント作成アプローチでは、可能なすべてのフィールドを単純にリストアップし、「異なるシナリオに基づいて異なるフィールドを選択してください」といったテキスト記述を使用することがよくあります。このアプローチは正確でも開発者フレンドリーでもなく、しばしば混乱を招きます。ApidogはJSONスキーマのoneOf、anyOf、allOf機能をサポートしており、これらの複雑な複合データ構造をAPIドキュメントで正確に記述できます。
3つの組み合わせモードを理解する
JSONスキーマでは、oneOf、anyOf、allOfは複数のサブスキーマを組み合わせるために使用されますが、それぞれ異なる論理的な意味を持ちます。
- allOf: 複数のルールを組み合わせ、すべてが一致することを要求します
- anyOf: 少なくとも1つの一致が必要で、複数の合致も許容されます
- oneOf: 厳密に1つのスキーマに一致する必要があり、ゼロまたは複数のスキーマに一致すると失敗します
Apidogでの組み合わせモードの設定
Apidogでは、これらの組み合わせモードを使用する2つの方法を提供しています。
ビジュアルエディタのアプローチ
最初の方法は、ビジュアル編集パネルを使用します。プロジェクト内で「データモデル」をクリックして新しいモデルを作成し、タイプ選択から「組み合わせモード」を見つけます。必要なoneOf、anyOf、またはallOfモードを選択し、各サブスキーマの具体的なデータ構造を定義します。

JSONスキーマコードエディタ
2番目のアプローチは、JSONスキーマコードを直接編集することです。データモデル編集パネルで、コードモードに切り替えてJSONスキーマを直接記述し、これらの論理的な組み合わせパターンを定義できます。この方法は、JSONスキーマに詳しい開発者にとってより直接的です。

APIエンドポイントでのこれらのパターンの適用
データモデルを定義したら、APIドキュメントで使用できます。インターフェースのリクエストパラメータを編集する際、ボディタイプをJSONとして選択し、データ構造セクションで、作成した「データモデル」を参照するか、直接「組み合わせモード」を選択して複雑なパラメータ構造を定義できます。

同じ原則がレスポンスデータの定義にも適用されます。戻り値のレスポンスセクションでレスポンス例を追加する際、組み合わせモードを使用して異なるシナリオのレスポンス形式を記述できます。この方法により、開発者は異なる状況でどのようなデータ構造が返されるかを明確に理解できます。
実世界のユースケース
allOf: 複数の構造を組み合わせる
allOfは複数の構造をまとめます。これは選択ではなく、積み重ねです。allOfはフィールドの階層を変更せず、すべてのフィールドが同じオブジェクト内に配置されます。単に同じデータに複数のルールを重ねるだけです。「論理AND」と考えてください。すべてのサブ構造の制約が満たされる必要があります。
例えば、このJSONスキーマ:
{
"allOf": [
{
"description": "Basic user information",
"type": "object",
"properties": {
"id": { "type": "integer" },
"name": { "type": "string" }
},
"required": ["id", "name"]
},
{
"description": "Contact information",
"type": "object",
"properties": {
"email": { "type": "string", "format": "email" },
"phone": { "type": "string" }
},
"required": ["email"]
}
]
}
このスキーマは、最終的なデータが「基本ユーザー情報」と「連絡先情報」の両方の構造を同時に満たす必要があることを意味します。
言い換えれば、リクエストボディにはid、name、emailが含まれている必要があり、phoneはオプションです。
有効なデータ:
{
"id": 1001,
"name": "John Doe",
"email": "john@example.com",
"phone": "1-800-000-0000"
}
無効なデータ:
{
"id": 1001,
"name": "John Doe"
}
これは必須のemailフィールドが欠けており、2番目の構造を満たしていません。
このアプローチは、複雑なオブジェクトを分割するのに適しています。ユーザー情報、注文詳細、設定項目などは、機能モジュールごとに独立した構造に分割し、allOfを使用して組み合わせることができます。これらの構造の一部を必要とする他のインターフェースは、冗長な定義なしに直接それらを参照できます。
anyOf: 少なくとも1つの条件を満たす
anyOfは複数の可能な構造をリストアップし、データがそれらのうち少なくとも1つに準拠していれば有効と見なされます。複数の条件が満たされているかどうかは気にせず、一意のマッチングも要求しません。
例えば、識別子フィールドはメールアドレスまたは電話番号である場合があります。これら2つの形式は明確に異なりますが、どちらも「ユーザーログイン資格情報」のカテゴリに属します。
この「AまたはBの可能性がある」という意図を明確に表現するためにanyOfを使用できます。
{
"type": "object",
"properties": {
"identifier": {
"description": "User identifier: can be email or phone number",
"anyOf": [
{
"title": "Email format",
"description": "Must be a valid email address",
"type": "string",
"format": "email"
},
{
"title": "Phone format",
"description": "Must be a valid international phone number",
"type": "string",
"pattern": "^\\+?[1-9]\\d{1,14}$"
}
]
},
"password": {
"type": "string",
"minLength": 6,
"description": "Login password, at least 6 characters"
}
},
"required": ["identifier", "password"],
"description": "User login request parameters"
}
この構造は、識別子がメール形式または電話番号形式のいずれかを満たしていれば有効と見なされる文字列であることを意味します。
有効なデータ:
{
"identifier": "test@example.com",
"password": "123456"
}
{
"identifier": "+1-800-000-0000",
"password": "123456"
}
無効なデータ:
{
"identifier": "abc",
"password": "123456"
}
「abc」はメールアドレスでも有効な電話番号形式でもなく、どの条件も満たしていません。
oneOf: 厳密に1つのオプションを選択する
oneOfは複数の可能な構造をリストアップし、データはそれらのうち厳密に1つに準拠する必要があります。排他性を強調しており、1つだけを選択でき、それ以上でもそれ以下でもありません。
例えば、支払い方法:支払いを完了するには、ユーザーはクレジットカード、WeChat Pay、またはAlipayのいずれかを選択する必要があり、同時に2つの方法を使用したり、何も選択しないことはできません。この「単一選択」ロジックをoneOfを使用して定義できます。
{
"properties": {
"paymentMethod": {
"description": "Payment method, must choose exactly one",
"oneOf": [
{
"title": "Credit Card Payment",
"description": "Pay with credit card, requires card number and expiry date",
"type": "object",
"properties": {
"type": { "const": "credit_card" },
"cardNumber": { "type": "string" },
"expiryDate": { "type": "string" }
},
"required": ["type", "cardNumber", "expiryDate"],
"additionalProperties": false
},
{
"title": "WeChat Pay",
"description": "Pay through WeChat, requires user's openid",
"type": "object",
"properties": {
"type": { "const": "wechat" },
"openid": { "type": "string" }
},
"required": ["type", "openid"],
"additionalProperties": false
},
{
"title": "Alipay Payment",
"description": "Pay through Alipay, requires account ID",
"type": "object",
"properties": {
"type": { "const": "alipay" },
"accountId": { "type": "string" }
},
"required": ["type", "accountId"],
"additionalProperties": false
}
]
}
}
}
この定義は、paymentMethodが3つのサブ構造のうち1つのみに一致できるオブジェクトであることを意味します。
有効な例:
{
"paymentMethod": {
"type": "wechat",
"openid": "wx_123456"
}
}
{
"paymentMethod": {
"type": "credit_card",
"cardNumber": "4111111111111111",
"expiryDate": "12/25"
}
}
無効な例:
{
"paymentMethod": {
"type": "wechat",
"openid": "wx_123",
"accountId": "2088102"
}
}
typeが「wechat」であっても、accountIdが存在すると複数の構造に一致する可能性があり、oneOfが失敗する原因となります。"additionalProperties": false
を追加することで、この混乱を防ぎ(追加のフィールドが許可されないことを意味します)、各構造が自身の定義されたフィールドのみを許可するようにします。ApidogはadditionalPropertiesの視覚的な設定をサポートしています。
複数の異なるタイプ間で排他的な選択を行う必要がある場合、oneOfはこれを表現する最も直接的で信頼性の高い方法です。
適切な組み合わせモードの選択
組み合わせモードの選択は、主にビジネスロジックに依存します。
- 複数のパターンを組み合わせて継承する必要がある場合は、allOfを使用します。
- 柔軟なオプションの組み合わせが必要な場合は、anyOfを使用します。
- 厳密な排他的選択が必要な場合は、oneOfを使用します。
それぞれの役割を理解することで、APIドキュメントで複雑なデータ構造を正確に記述し、インターフェースの利用者がパラメータをどのように渡すべきかを即座に明確にすることができます。
結論
Apidogの包括的なJSONスキーマサポートは、開発者が最も複雑なパラメータ構造であっても、正確で明確なAPIドキュメントを作成できるようにします。oneOf、anyOf、allOfの組み合わせを活用することで、曖昧さを排除し、APIコンシューマに非常に明確なガイダンスを提供できます。
高度なAPIドキュメントの力を体験する準備はできましたか?今すぐApidogを試して、複雑なAPIパラメータを正確かつ明確に管理することがいかに簡単になるかを確認してください。