Skip to content

[Feature] [ama-sdk]: Proper support of polymorphism inheritance #3870

@kpanot

Description

@kpanot

Package version

14.0.0

Reproduction steps

Following internal requirement regarding the way to write polymorphism extension, the following items need to be fulfill by the SDKs:

openapi: 3.0.0
info:
  description: This is a sample SDK
  version: 1.0.0
  title: Otter Example SDK
tags:
  - name: dummy
    description: Dummy operations
paths:
  /animal:
    get:
      tags:
        - "dummy"
      summary: Animal get
      description: Get an animal
      operationId: animalGet
      responses:
        200:
          description: "Successful operation"
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
components:
  schemas:
    Pet:
      type: object
      required:
        - pet_type
      properties:
        pet_type:
          type: string
          enum: [cat, dog] # <- optional enum, can be forgotten in the declaration without changing generated code
      discriminator:
        propertyName: petType
        mapping: # <- mandatory
          dog: "#/components/schemas/Dog"
          cat: "#/components/schemas/Cat"
    Dog:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            bark:
              type: boolean
            breed:
              type: string
              enum: [Dingo, Husky, Retriever, Shepherd]
    Cat:
      allOf:
        - $ref: '#/components/schemas/Pet'
        - type: object
          properties:
            hunts:
              type: boolean
            age:
              type: integer

Current result

API function with prototype:

class {
  async animalGet(data: DummyApiAnimalGetRequestData, metadata?: RequestMetadata<string, 'application/json'>): Promise<Pet>;
}

cat.ts file content:

export interface Cat extends Pet {
  hunts?: boolean;
  age?: number;
}

/** Array of PetTypeEnum items */
export const LIST_PET_TYPE_ENUM = ['cat', 'dog'] as const;

/** List of available values for PetTypeEnum */
export type PetTypeEnum = 'cat' | 'dog';

pet.ts file content:

export interface Pet {
  /** @see PetTypeEnum */
  pet_type: PetTypeEnum;
}

/** Array of PetTypeEnum items */
export const LIST_PET_TYPE_ENUM = ['cat', 'dog'] as const;

/** List of available values for PetTypeEnum */
export type PetTypeEnum = 'cat' | 'dog';

(dog.ts is similar to cat.ts)

Expected result

  • The API function with prototype should return possible children interfaces only (per definition a component with discriminator can be seen as abstract and can not be the result of an API):
class {
  async animalGet(data: DummyApiAnimalGetRequestData, metadata?: RequestMetadata<string, 'application/json'>): Promise<Cat | Dog>;
}
  • The cat.ts file content should avoid duplication, enforce discriminator value and offer check function:
export interface Cat extends Pet {
  pet_type: 'cat'; // <- enforced discriminator value
  hunts?: boolean;
  age?: number;
}

/**
  * Determine if object is a {@link Cat}
  * @param obj Object to check
  */
export const isCat = (obj: Pet): obj is Cat => {
  return obj.pet_type === 'cat';
}
  • (The file pet.ts can remained unchanged)

Additional comments

(internal) References

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions