Inheritance and Polymorphism with AllOf
APIMatic's SDKs support allOf types defined in OpenAPI specifications. This feature allows you to define schemas that inherit from multiple definitions, ensuring that an object adheres to all specified schemas simultaneously. This approach promotes modular and reusable schema definitions.
Configure AllOf in your OpenAPI Definition
Here is an example of an allOf type where discriminator is position defined in OpenAPI definition:
components:
schemas:
User:
type: object
properties:
position:
type: string
name:
type: string
email:
type: string
format: email
discriminator:
propertyName: position
mapping:
Empl: Employee
Adm: Admin
User: User
Admin:
allOf:
- $ref: '#/components/schemas/User'
- type: object
properties:
permissions:
type: array
items:
type: string
Employee:
allOf:
- $ref: '#/components/schemas/User'
- type: object
properties:
role:
type: string
In the above example:
- The
Userschema defines common properties. - The
Adminschema extends theUserschema and addspermissions. - The
Employeeschema extends theUserschema and addsrole.
Model Definitions in SDKs
note
- If
allOfis used with a discriminator, the SDK handles type resolution for polymorphic schemas. - If
allOfis used without a discriminator, the SDK merges all referenced properties into a single structure.
Here is how inheritance and polymorphism affects the models in APIMatic SDKs when the allOf construct is used.
- TypeScript
- Java
- Python
- .NET
- Go
- PHP
- Ruby
export interface User {
name?: string;
email?: string;
}
export interface Admin extends User {
permissions?: string[];
}
export interface Employee extends User {
role?: string;
}
public class User {
private String name;
private String email;
}
public class Admin extends User {
private List<String> permissions;
}
public class Employee extends User {
private String role;
}
class User(object):
def __init__(self,
name=None,
email=None):
class Admin(User):
def __init__(self,
name=None,
email=None,
permissions=None):
super(Admin, self).__init__(name, email)
class Employee(User):
def __init__(self,
name=None,
email=None,
role=None):
super(Employee, self).__init__(name, email)
public class User
{
public string Name { get; set; }
public string Email { get; set; }
}
public class Admin : User
{
public List<string> Permissions { get; set; }
}
public class Employee : User
{
public string Role { get; set; }
}
type User struct {
Name *string `json:"name,omitempty"`
Email *string `json:"email,omitempty"`
}
type Admin struct {
User
Permissions []string `json:"permissions,omitempty"`
}
type Employee struct {
User
Role string `json:"role,omitempty"`
}
class User
{
/**
* @var string|null
*/
private $name;
/**
* @var string|null
*/
private $email;
}
class Admin extends User
{
/**
* @var string[]|null
*/
private $permissions;
}
class Employee extends User
{
/**
* @var string|null
*/
private $role;
}
class User < BaseModel
# @return [String]
attr_accessor :name
# @return [String]
attr_accessor :email
class Admin < User
# @return [Array[String]]
attr_accessor :permissions
class Employee < User
# @return [String]
attr_accessor :role
Any endpoint that takes in an argument of type User will also be compatible with types Admin and Employee. Take the following example of an endpoint CreateUser that takes in the argument of type User.
- TypeScript
- Java
- Python
- .NET
- Go
- PHP
- Ruby
async () => {
const admin: Admin = { name: 'Alice', email: 'alice@example.com', permissions: ['read', 'write'] };
await apiController.createUser(admin);
const employee: Employee = { name: 'Bob', email: 'bob@example.com', role: 'Manager' };
await apiController.createUser(employee);
};
Admin admin = new Admin.Builder()
.name("Alice")
.email("alice@example.com")
.permissions(Collections.singletonList("read", "write"))
.build();
apiController.createUser(admin);
Employee employee = new Employee.Builder()
.name("Bob")
.email("bob@example.com")
.role("Manager")
.build();
apiController.createUser(employee);
admin = Admin(name="Alice", email="alice@example.com", permissions=["read", "write"])
api_controller.create_user(admin)
employee = Employee(name="Bob", email="bob@example.com", role="Manager")
api_controller.create_user(employee)
Admin admin = new Admin
{
Name = "Alice",
Email = "alice@example.com",
Permissions = new List<string> { "read", "write" }
};
apiController.CreateUser(admin);
Employee employee = new Employee
{
Name = "Bob",
Email = "bob@example.com",
Role = "Manager"
};
apiController.CreateUser(employee);
admin := Admin{
User: User{
Name: "Alice",
Email: "alice@example.com"
},
Permissions: []string{"read", "write"}
}
apiController.CreateUser(admin);
employee := Employee{
User: User{
Name: "Bob",
Email: "bob@example.com"
},
Role: "Manager"
}
apiController.CreateUser(employee);
$admin = AdminBuilder::init()
->name("Alice")
->email("alice@example.com")
->permissions(["read", "write"])
->build();
$client->getApiController()->createUser($admin);
$employee = EmployeeBuilder::init()
->name("Bob")
->email("bob@example.com")
->role("Manager")
->build();
$client->getApiController()->createUser($employee);
admin = Admin.new(name: "Alice", email: "alice@example.com", permissions: ["read", "write"])
api_controller.create_user(admin)
employee = Employee.new(name: "Bob", email: "bob@example.com", role: "Manager")
api_controller.create_user(employee)
Key Benefits
- Re-usability: Promotes schema reuse by allowing composition.
- Clarity: Simplifies schema definitions by breaking down complex models into smaller components.