tapir icon indicating copy to clipboard operation
tapir copied to clipboard

Allow to retrieve schema type parameters full name

Open yakivy opened this issue 2 years ago • 7 comments

Hi there, I faced the following issue:

import sttp.tapir._
import sttp.tapir.generic.auto._

object A {
  case class B(a: String)
}
object B {
  case class B(b: Int)
}
case class Value[C](c: C)

Schema.derivedSchema[A.B].name //Some(SName(Playground.A.B,List()))
Schema.derivedSchema[Value[A.B]].name //Some(SName(Playground.Value,List(B)))
Schema.derivedSchema[Value[B.B]].name //Some(SName(Playground.Value,List(B)))

Specifically Value[A.B] and Value[B.B] produce the same Schema.SName that causes a conflict in the docs components.

As a temp fix I copied derivation logic: https://github.com/softwaremill/tapir/blob/2f38f0c9562056340c1cf8f634047287826fab5f/core/src/main/scala-2/sttp/tapir/generic/auto/SchemaMagnoliaDerivation.scala#L49 with a small change: .map(_.short) -> .map(_.full)

Probably this is not a great final fix as an argument with name typeParameterShortNames contains a full type name now, but you should get an idea of the possible solution.

What do you think?

yakivy avatar Jan 18 '24 18:01 yakivy

cc: @jackcviers

yakivy avatar Jan 18 '24 18:01 yakivy

Hm maybe we should use some heuristic, instead of just "short" vs "full", include all name components (as divided by .) from the first one that starts with a capital letter (and which hence is an object / class)?

adamw avatar Jan 18 '24 19:01 adamw

@adamw both will work for me. Anyway there is another transformation step from SName to component name in docs options, for example sttp.tapir.docs.openapi.OpenAPIDocsOptions#schemaName, which looks like:

  private[docs] val defaultSchemaName: SName => String = info => {
    val shortName = info.fullName.split('.').last
    (shortName +: info.typeParameterShortNames).mkString("_")
  }

In my case I added .replaceAll("\\.", "_"), with name components I'll join them by _

yakivy avatar Jan 18 '24 19:01 yakivy

@yakivy yes, although during schema generation, there's also a de-duplication step, which in case of classes with same fullname, but different schema names, add a 2 (or 3...) suffix, so this would be not ideal, but not a bug.

Anyway, we should apply the same logic here. Maybe you'd like to try a PR? :)

adamw avatar Jan 22 '24 16:01 adamw

@adamw no problem, will try to find a bit of time this week. How strict is tapir regarding to binary compatibility? Is it ok to rename type params field like:

case class SName(fullName: String, typeParameterNames: List[String])

or better to keep it as is with a fat warning in docs?

yakivy avatar Jan 22 '24 16:01 yakivy

Great :) In case of classes in core, we need to maintain binary compatibility. So I think the name is fixed, we'll have to resort to comments. You can check if your changes are binary-compatible using mimaCheckBinaryCompatibility while in core.

adamw avatar Jan 22 '24 16:01 adamw

@adamw PR is ready for review

yakivy avatar Feb 05 '24 16:02 yakivy