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
User
schema defines common properties. - The
Admin
schema extends theUser
schema and addspermissions
. - The
Employee
schema extends theUser
schema and addsrole
.
Model Definitions in SDKs
note
- If
allOf
is used with a discriminator, the SDK handles type resolution for polymorphic schemas. - If
allOf
is 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.