I was wondering why subtypeNameToSchemaName in SchemaMagnoliaDerivation always recalculates names based on TypeName, instead eg. attempting to get those names from known Schema.name and if it doesn’t exist then fallback to TypeName.
IN MY HEAD that would/could resolve issue of semiauto derivation loosing type info of params.
That’s a good question - I don’t know off the top of my head. Maybe you can try changing and seeing what breaks? There’s a lot of tests in openApiDocs which should help to quickly verify the behavior.
I did change it, tests passed, but it seems there is no value in it, that change or not semiauto derivation for anything with generic params is completly broken.
Is that semiauto issue magnolia bug? or some scala type system corner case?
Wonder if we could have typeclass for each generic argument to hack around it
package com.test
import io.circe.generic.auto._
import sttp.apispec.openapi.circe.yaml.RichOpenAPI
import sttp.tapir._
import sttp.tapir.docs.openapi.OpenAPIDocsInterpreter
import sttp.tapir.json.circe.jsonBody
object Test extends App {
lazy implicit val someValueStringSchema: Schema[SomeValueString] = Schema.derived
lazy implicit val someValueIntSchema: Schema[SomeValueInt] = Schema.derived
lazy implicit val hasStringTreeSchema: Schema[HasStringTree] = Schema.derived
lazy implicit val hasIntTreeSchema: Schema[HasIntTree] = Schema.derived
@inline
implicit def adtTreeSchema[A: Schema]: Schema[AdtTree[A]] = Schema.derived[AdtTree[A]]
val endpoint1 = endpoint
.put
.name("test1")
.in("test" / "1")
.in(jsonBody[AdtTree[SomeValueString]])
val endpoint2 = endpoint
.put
.name("test2")
.in("test" / "2")
.in(jsonBody[AdtTree[SomeValueInt]])
val endpoints = List(endpoint1, endpoint2)
val yamlString: String = OpenAPIDocsInterpreter()
.toOpenAPI(endpoints, "test", "v1")
.toYaml
println(yamlString)
}
sealed trait AdtTree[A]
object AdtTree {
final case class AdtLeaf[A](a: A) extends AdtTree[A]
final case class AdtNode[A](trees: List[AdtTree[A]]) extends AdtTree[A]
}
final case class SomeValueString(value: String)
final case class SomeValueInt(value: Int)
final case class HasStringTree(value: String, tree: AdtTree[SomeValueString])
final case class HasIntTree(value: String, tree: AdtTree[SomeValueInt])
Oh … that’s “interesting”. I’d have to take a look. As a work-around, you should be able to customise the semi-auto-derived schemas with correct names, as described here.
lazy implicit val hasIntTreeSchema: Schema[HasIntTree] = Schema.derived