All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sttp.tapir.docs.apispec.schema.ToSchemaReference.scala Maven / Gradle / Ivy

There is a newer version: 1.11.5
Show newest version
package sttp.tapir.docs.apispec.schema

import sttp.apispec.{Schema => ASchema}
import sttp.tapir.{Schema => TSchema}
import sttp.tapir.Schema.Title
import sttp.tapir.docs.apispec.schema.TSchemaToASchema.{tDefaultToADefault, tExampleToAExample}

private[schema] class ToSchemaReference(
    keyToId: Map[SchemaKey, SchemaId],
    keyToSchema: Map[SchemaKey, TSchema[_]],
    refRoot: String = "#/components/schemas/"
) {
  def map(schema: TSchema[_], name: TSchema.SName): ASchema = {
    val key = SchemaKey(schema, name)
    val maybeId = keyToId.get(key)
    var result = map(key.name, maybeId)
    keyToSchema.get(key).foreach { originalSchema =>
      // checking if we don't need to enrich the reference, as it might contain additional usage-site specific properties
      // the differently customised properties are reset to their default values in ToKeyedSchemas (#1203)
      if (originalSchema.description != schema.description) result = result.copy(description = schema.description)
      if (originalSchema.default != schema.default) result = result.copy(default = tDefaultToADefault(schema))
      if (originalSchema.encodedExample != schema.encodedExample) result = result.copy(examples = tExampleToAExample(schema).map(List(_)))
      if (originalSchema.deprecated != schema.deprecated && schema.deprecated) result = result.copy(deprecated = Some(schema.deprecated))
      if (originalSchema.attributes.get(Title.Attribute) != schema.attributes.get(Title.Attribute))
        result = result.copy(title = schema.attributes.get(Title.Attribute).map(_.value))
    }
    result
  }

  /** When mapping a reference used directly (which contains a name only), in case there are multiple schema keys with that name, we use the
    * one with a smaller number of fields - as these duplicates must be because one is a member of an inheritance hierarchy; then, we choose
    * the variant without the extra discriminator field (#2358).
    *
    * When mapping a referenced used in a discriminator, we choose the variant with the higher number of fields in [[mapDiscriminator]].
    */
  def mapDirect(name: TSchema.SName): ASchema =
    map(name, keyToId.filter(_._1.name == name).toList.sortBy(_._1.fields.size).headOption.map(_._2))

  def mapDiscriminator(name: TSchema.SName): ASchema =
    map(name, keyToId.filter(_._1.name == name).toList.sortBy(-_._1.fields.size).headOption.map(_._2))

  private def map(name: TSchema.SName, maybeId: Option[SchemaId]): ASchema = maybeId match {
    case Some(id) => ASchema.referenceTo(refRoot, id)
    case None     => ASchema.referenceTo("", name.fullName) // no reference to internal model found. assuming external reference
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy