tapir icon indicating copy to clipboard operation
tapir copied to clipboard

[BUG] AsyncAPI generated schema issue when using Configuration.withDiscriminator

Open KamilPostrozny opened this issue 1 year ago • 0 comments

Tapir version: 1.8.2

Scala version: 3.3.1

AsyncAPI studio can't parse the generated yaml when using Configuration.default.withDiscriminator for ADT type or simple enum.

Given this minimal example

//> using dep com.softwaremill.sttp.tapir::tapir-zio-http-server:1.8.2
//> using dep com.softwaremill.sttp.tapir::tapir-asyncapi-docs:1.8.2
//> using dep com.softwaremill.sttp.apispec::asyncapi-circe-yaml:0.7.1
//> using dep com.softwaremill.sttp.tapir::tapir-jsoniter-scala:1.8.2
//> using dep "com.github.plokhotnyuk.jsoniter-scala::jsoniter-scala-macros:2.24.2"

import com.github.plokhotnyuk.jsoniter_scala.core.JsonValueCodec
import com.github.plokhotnyuk.jsoniter_scala.macros.JsonCodecMaker
import sttp.apispec.asyncapi.circe.yaml.*
import sttp.capabilities.zio.ZioStreams
import sttp.tapir.Schema
import sttp.tapir.*
import sttp.tapir.docs.asyncapi.AsyncAPIInterpreter
import sttp.tapir.generic.Configuration
import sttp.tapir.generic.auto.*
import sttp.tapir.json.jsoniter.*

object TapirADT extends App:
  val end = endpoint.in("test").out(webSocketBody[Topic, CodecFormat.Json, Topic, CodecFormat.Json](ZioStreams))
  val api = AsyncAPIInterpreter().toAsyncAPI(end, "Websocket", "1.0").toYaml
  println(api)

sealed trait Topic

object Topic:
  sealed trait PublicTopic  extends Topic
  sealed trait PrivateTopic extends Topic
  case object PublicParts   extends PublicTopic
  case object PrivateParts  extends PrivateTopic

  given JsonValueCodec[Topic] = JsonCodecMaker.make

  given Schema[Topic] = {
    given Configuration = Configuration.default.withDiscriminator("type")
    Schema.derived[Topic]
  }

Which generates this yaml

info:
  title: Websocket
  version: '1.0'
channels:
  /test:
    subscribe:
      operationId: onTest
      message:
        $ref: '#/components/messages/Topic'
    publish:
      operationId: sendTest
      message:
        $ref: '#/components/messages/Topic'
    bindings:
      ws:
        method: GET
components:
  schemas:
    Topic:
      oneOf:
      - $ref: '#/components/schemas/PrivateParts'
      - $ref: '#/components/schemas/PublicParts'
      discriminator:
        propertyName: type
        mapping:
          PrivateParts: '#/components/schemas/PrivateParts'
          PublicParts: '#/components/schemas/PublicParts'
    PrivateParts:
      required:
      - type
      type: object
      properties:
        type:
          type: string
    PublicParts:
      required:
      - type
      type: object
      properties:
        type:
          type: string
  messages:
    Topic:
      payload:
        $ref: '#/components/schemas/Topic'
      contentType: application/json

You can see in the attached screenshot that AsyncAPI studio can't parse the generated yaml. The equivalent of this with simple (non websocket) endpoint for OpenAPI works fine while using Configuration.default.withDiscriminator.

Screenshot 2023-10-26 at 10 24 35

KamilPostrozny avatar Oct 26 '23 08:10 KamilPostrozny