Skip to content

Discriminator support to be aligned with OAS3 #1073

@francocm

Description

@francocm

Context

The overlap in specification between AsyncAPI and OpenAPI specs allows the combining of common models across both.

Example:

./models/foo.yaml
openapi: 3.1.0
info:
  title: foo-models
  description: Models for Foo
  contact:
    name: Foo Team
  version: 1.0.0
paths: { }
components:
  schemas:
    Foo:
      type: object
      properties:
        id:
          type: string
./apis/foo.openapi.ayml
openapi: "3.1.0"
info:
  title: "foo"
  description: "API Specifications for `foo`."
  version: "1.0.0"
servers:
  - url: http://localhost:8080/
    description: Local Dev
paths:
  /foo:
    get:
      summary: "Get Foos"
      description: "Get Foos"
      operationId: "getFoos"
      responses:
        "200":
          description: "OK"
          content:
            'application/json':
              schema:
                type: array
                items:
                  $ref: "../models/foo.yaml#/components/schemas/Foo"
./events/foo.asyncapi.ayml
asyncapi: 3.0.0
info:
  title: foo Events
  version: 1.0.0
servers:
  foo-local:
    host: localhost:1234
    protocol: foo
    description: Foo broker (local dev)
    security:
      - $ref: '#/components/securitySchemes/plainSecurity'
defaultContentType: application/json
channels:
  FooEvents:
    address: foo.events
    description: The topic on which foo events are published on.
    messages:
      fooQueriedEvent:
        $ref: '#/components/messages/fooQueriedEvent'
operations:
  'foo.queried':
    action: send
    channel:
      $ref: '#/channels/FooEvents'
    messages:
      - $ref: '#/channels/FooEvents/messages/fooQueriedEvent'
components:
  messages:
    fooQueriedEvent:
      name: fooQueriedEvent
      title: Foo Queried Event
      summary: Foo Queried Event
      description: Foo Queried Event
      contentType: application/json
      payload:
        $ref: '../models/foo.yaml#/components/schemas/Foo'
  securitySchemes:
    plainSecurity:
      type: plain
      description: Plain unauthenticated connection

Problem

It's quite evident that AsyncAPI in general has no compatibility issues with OpenAPI specifications.

However, the problem lies with the use of discriminator in a oneOf situation.

If I update ./models/foo.yaml to this:

openapi: 3.1.0
info:
  title: foo-models
  description: Models for Foo
  contact:
    name: Foo Team
  version: 1.0.0
paths: { }
components:
  schemas:
    Foo:
      type: object
      properties:
        id:
          type: string
        bazAttributes:
          $ref: '#/components/schemas/OneOfBazAttributes'
    OneOfBazAttributes:
      type: object
      properties:
        type:
          type: string
          enum: [ 'RealBaz', 'MockBaz' ]
      discriminator:
        propertyName: type
        mapping:
          RealBaz: '#/components/schemas/RealBazAttributes'
          MockBaz: '#/components/schemas/MockBazAttributes'
    RealBazAttributes:
      allOf:
        - $ref: '#/components/schemas/OneOfBazAttributes'
      type: object
      properties:
        bazId:
          type: string
    MockBazAttributes:
      allOf:
        - $ref: '#/components/schemas/OneOfBazAttributes'
      type: object
      properties:
        xyzId:
          type: string
Output Result
OpenAPI Works as expected
AsyncAPI Fails with "discriminator" property type must be string channels.FooEvents.messages.fooQueriedEvent.payload.properties.bazAttributes.discriminator

This is using the official asyncapi CLI binary provided by asyncapi/cli:2.6.0 docker image, but also any other AsyncAPI tool I could find.

Root Cause

From what I can understand, AsyncAPI implements discriminator using the schema that OpenAPI 2.x (Swagger) had, i.e.:

OneOfBazAttributes:
  type: object
  properties:
    type: 
      type: string
      enum: [ 'RealBazAttributes', 'MockBazAttributes' ]
  discriminator: type
# with the expectation of having the value of `type` matching
# the object name exactly as defined in the YAML

(although the AsyncAPI render does not render any oneOf options, but all validations now pass successfully).

OpenAPI moved to a newer schema in 3.x, and whilst AsyncAPI does not seem to have problems with the OpenAPI 3.x schema compatibility, the specific discriminator capability seems to still be stuck in the 2.x world.

As it is, I do not see any clean way to be able to support discriminator and both OpenAPI and AsyncAPI simultaneously, without fixing this issue, or rolling everything back to 2.x.

Proposal

Align the AsyncAPI spec around discriminator to that of OpenAPI 3.1.x, and release it as AsyncAPI 3.1.0.


Keen to see your thoughts.

Thanks anyone participating.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions