API parameters often have complex structures, with a single endpoint supporting multiple different parameter combinations. For example, a login endpoint might support username-password authentication, email-password authentication, or phone number verification codes. Payment endpoints can offer various methods like credit cards, debit cards or digital wallets, each requiring different fields.

Traditional API documentation approaches often simply list all possible fields and use text descriptions like "choose different fields based on different scenarios." This approach is neither precise nor developer-friendly, often leading to confusion. Apidog supports JSON Schema's oneOf, anyOf, and allOf features, allowing you to describe these complex composite schemas in your API documentation accurately.
Understanding the Three Schema Compositions
In JSON Schema, oneOf, anyOf, and allOf are used to combine multiple sub-schemas, but they have different logical meanings:
- allOf: Combines multiple rules, requiring all to match
- anyOf: At least one match is required, multiple matches are acceptable
- oneOf: Must match exactly one schema; matching zero or multiple schemas will fail
Setting Up Schema Composition in Apidog
Apidog provides two ways to use these schema composition:
1. Visual Editor Approach
The first method uses the visual editing panel. In your project, click "Schemas" to create a new one, then find "Schema Composition" in the data type selection. Choose the needed oneOf, anyOf, or allOf option, then define specific data structures for each sub-schema.

2. JSON Schema Code Editor
The second approach involves directly editing JSON Schema code. In the schema editing panel, you can switch to code mode and write JSON Schema directly to define these logical schema compositions. This method is more direct for developers familiar with JSON Schema.

Applying These Schema Compositions in API Endpoints
Once you've defined your schemas, you can use them in your API documentation. When editing endpoint request parameters, select Body type as JSON, then in the data schema section, you can reference the schema you just created, or directly select "Schema Composition" to define complex parameter structures.

The same principle applies to response data definitions. When adding response examples in the returned response section, you can use schema compositions to describe response formats for different scenarios. This way, developers can clearly understand what schemas will be returned in different situations.
Real-World Use Cases
allOf: Combining Multiple Schemas
allOf combines multiple schemas together - it's not about selection, but about stacking.
allOf doesn't change field hierarchy; all fields end up in the same object. It simply stacks multiple rules on the same schema. Think of it as "logical AND" - all sub-schemas constraints must be satisfied.
For example, this JSON Schema:
{
"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"]
}
]
}
This schema means: the final data must simultaneously satisfy both "basic user information" and "contact information" structures.
In other words, the request body must include id, name, and email, while phone is optional.
Valid data:
{
"id": 1001,
"name": "John Doe",
"email": "john@example.com",
"phone": "1-800-000-0000"
}
Invalid data:
{
"id": 1001,
"name": "John Doe"
}
This lacks the required email field and doesn't satisfy the second schema.
This approach is suitable for splitting complex objects. User information, order details, configuration items, etc., can all be divided into independent schemas by functional modules, then combined using allOf. Other endpoints that need part of these schemas can reference them directly without redundant definitions.
anyOf: Satisfying At Least One Condition
anyOf lists multiple possible schemas, and data is considered valid as long as it conforms to at least one of them. It doesn't care whether multiple conditions are satisfied, nor does it require unique matching.
For example, an identifier field might be an email or a phone number. These two formats are distinctly different, but both belong to the category of "user login credentials."
You can use anyOf to clearly express this "can be A or B" intention:
{
"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"
}
This structure means: identifier is a string that's considered valid as long as it satisfies either email format or phone number format.
Valid data:
{
"identifier": "test@example.com",
"password": "123456"
}
{
"identifier": "+1-800-000-0000",
"password": "123456"
}
Invalid data:
{
"identifier": "abc",
"password": "123456"
}
"abc" is neither an email nor a valid phone number format, satisfying none of the conditions.
oneOf: Choose Exactly One Option
oneOf lists multiple possible schemas, and data must conform to exactly one of them. It emphasizes exclusivity - you can only choose one, not more, not less.
For example, payment methods: to complete a payment, users must choose one of credit card, debit card, or other digital methods, but cannot use two methods simultaneously, nor can they choose none. You can define this "single-choice" logic using 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": "debit card",
"description": "Pay through debit card, requires user's openid",
"type": "object",
"properties": {
"type": { "const": "debit card" },
"openid": { "type": "string" }
},
"required": ["type", "openid"],
"additionalProperties": false
},
{
"title": "digital wallets",
"description": "Pay through digital wallets, requires account ID",
"type": "object",
"properties": {
"type": { "const": "digital wallets" },
"accountId": { "type": "string" }
},
"required": ["type", "accountId"],
"additionalProperties": false
}
]
}
}
}
This definition means: paymentMethod is an object that can only match one of the three sub-schemas.
Valid examples:
{
"paymentMethod": {
"type": "Credit Card Payment",
"cardNumber": { "type": "string" },
"expiryDate": { "type": "string" }
}
}
Invalid example:
{
"paymentMethod": {
"type": "Credit Card Payment",
"accountId": "2088102"
}
}
When you need to make exclusive choices between multiple distinct types, oneOf is the most direct and reliable way to express this.
Choosing the Right Schema Composition
The choice of schema composition mainly depends on your business logic:
- Use allOf when you need to combine and inherit multiple schemas
- Use anyOf when you need flexible optional shemas
- Use oneOf when you need strict exclusive choices
Understanding their respective roles allows your API documentation to accurately describe complex data structures, making it immediately clear to API users how to pass parameters.
Conclusion
Apidog's comprehensive JSON Schema support empowers developers to create precise, clear API documentation for even the most complex parameter structures. By leveraging oneOf, anyOf, and allOf combinations, you can eliminate ambiguity and provide crystal-clear guidance to API consumers.
Ready to experience the power of advanced API documentation? Try Apidog today and see how easy it becomes to manage complex API parameters with precision and clarity.



