anyOf Handling
Soxom interprets anyOf as oneOf to avoid type explosion and provide predictable SDK types.
The Problem with anyOf
Section titled “The Problem with anyOf”In OpenAPI, anyOf means “match one or more of these schemas.” This creates challenges for type generation:
# OpenAPI anyOfValue: anyOf: - type: string - type: integer - type: array items: type: stringTheoretical valid values:
"hello"- string only42- integer only["a", "b"]- array only- But also… combinations? The spec is ambiguous.
Type explosion problem:
// What type should we generate?type Value = | string | number | string[] | (string & number) // Impossible | (string & string[]) // Impossible | (number & string[]) // Impossible | (string & number & string[]) // ImpossibleSoxom’s Approach
Section titled “Soxom’s Approach”This provides:
- Predictable types
- Clean SDK code
- Better developer experience
- Consistent behavior across languages
Example
Section titled “Example”# OpenAPIResult: anyOf: - $ref: '#/components/schemas/Success' - $ref: '#/components/schemas/Error'Soxom generates (same as oneOf):
// TypeScripttype Result = Success | Error;# PythonResult = Success | ErrorRationale
Section titled “Rationale”Alignment with Reality
Section titled “Alignment with Reality”In practice, APIs using anyOf almost always mean oneOf:
- Response is either a success OR an error
- Value is either a string OR a number
- Data is either format A OR format B
True “any combination” semantics are rare and usually indicate spec issues.
Predictable SDKs
Section titled “Predictable SDKs”Treating anyOf as oneOf ensures:
- Type-safe code generation
- Clear discriminator handling
- Consistent serialization/deserialization
- Better IDE autocomplete
Industry Standard
Section titled “Industry Standard”This approach aligns with other SDK generators like Speakeasy, providing familiar behavior for API developers.
Recommendations
Section titled “Recommendations”Use oneOf Instead
Section titled “Use oneOf Instead”When you mean “one of these options”, use oneOf:
# RecommendedPaymentMethod: oneOf: - $ref: '#/components/schemas/CreditCard' - $ref: '#/components/schemas/BankAccount' discriminator: propertyName: typeUse allOf for Combinations
Section titled “Use allOf for Combinations”When you need combined properties, use allOf:
# For combining schemasEmployee: allOf: - $ref: '#/components/schemas/Person' - $ref: '#/components/schemas/Employment'Avoid anyOf
Section titled “Avoid anyOf”If you have anyOf in your spec, consider:
- Convert to oneOf if values are mutually exclusive
- Convert to allOf if values should be combined
- Restructure if neither fits
Migration Examples
Section titled “Migration Examples”anyOf to oneOf
Section titled “anyOf to oneOf”Before:
Response: anyOf: - $ref: '#/components/schemas/SuccessResponse' - $ref: '#/components/schemas/ErrorResponse'After:
Response: oneOf: - $ref: '#/components/schemas/SuccessResponse' - $ref: '#/components/schemas/ErrorResponse' discriminator: propertyName: status mapping: success: '#/components/schemas/SuccessResponse' error: '#/components/schemas/ErrorResponse'anyOf to Separate Types
Section titled “anyOf to Separate Types”Before:
# Trying to express "string or number"FlexibleId: anyOf: - type: string - type: integerAfter:
# Just use string - IDs should be strings anywayFlexibleId: type: string description: ID can be numeric but is always transmitted as stringEdge Cases
Section titled “Edge Cases”Nullable with anyOf
Section titled “Nullable with anyOf”# Often seen for nullable typesMaybeUser: anyOf: - $ref: '#/components/schemas/User' - type: 'null'Soxom handles this as a nullable type:
type MaybeUser = User | null;Single-Item anyOf
Section titled “Single-Item anyOf”# Sometimes used for inheritanceExtendedUser: anyOf: - $ref: '#/components/schemas/User' properties: extra_field: type: stringSoxom treats this as simple extension (like allOf).
Summary
Section titled “Summary”| Keyword | Use When | Soxom Behavior |
|---|---|---|
oneOf | Mutually exclusive options | Union type with discriminator |
allOf | Combining/inheriting schemas | Composition/inheritance |
anyOf | Avoid if possible | Treated as oneOf |
Next Steps
Section titled “Next Steps”- oneOf (Unions) - Proper union type usage
- allOf (Composition) - Type composition
- Naming - Naming conventions