Skip to content

Commit 7a4a4f9

Browse files
author
Andrea Fiore
committed
Introduce FieldDefinition
This is intended to associate a definition to a field name, allowing to include the latter in error messages
1 parent ebeffa5 commit 7a4a4f9

File tree

7 files changed

+61
-30
lines changed

7 files changed

+61
-30
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ groups into a single Swagger API description.
286286

287287
``` {.scala}
288288
scala> PathGroup.aggregate(apiInfo, List(PetsRoute, DinosRoute))
289-
res13: cats.data.ValidatedNel[com.timeout.docless.swagger.SchemaError,com.timeout.docless.swagger.APISchema] = Invalid(NonEmptyList(MissingDefinition(RefWithContext(TypeRef(Dino),ResponseContext(Get,/dinos/{id})))))
289+
res13: cats.data.ValidatedNel[com.timeout.docless.swagger.SchemaError,com.timeout.docless.swagger.APISchema] = Invalid(NonEmptyList(MissingDefinition(RefWithContext(TypeRef(Dino,None),ResponseContext(Get,/dinos/{id})))))
290290
```
291291

292292
The `aggregate` method will also verify that the schema definitions

src/main/scala/com/timeout/docless/encoders/Swagger.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,14 +75,14 @@ object Swagger {
7575
}
7676

7777
implicit val schemaRefEnc = Encoder.instance[JsonSchema.Ref] {
78-
case ArrayRef(id) =>
78+
case ArrayRef(id, _) =>
7979
Json.obj(
8080
"type" -> Json.fromString("array"),
8181
"items" -> Json.obj(
8282
"$ref" -> Json.fromString(s"#/definitions/$id")
8383
)
8484
)
85-
case TypeRef(id) =>
85+
case TypeRef(id, _) =>
8686
Json.obj("$ref" -> Json.fromString(s"#/definitions/$id"))
8787
}
8888

src/main/scala/com/timeout/docless/schema/JsonSchema.scala

+40-12
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.timeout.docless.schema
22

3+
import com.timeout.docless.schema.JsonSchema.NamedDefinition
34
import com.timeout.docless.swagger.Responses.Response
45
import io.circe._
56
import io.circe.syntax._
@@ -19,6 +20,9 @@ trait JsonSchema[A] extends JsonSchema.HasRef {
1920

2021
def relatedDefinitions: Set[JsonSchema.Definition]
2122

23+
def fieldDefinitions: Set[JsonSchema.NamedDefinition] =
24+
relatedDefinitions.collect { case d: NamedDefinition => d }
25+
2226
def jsonObject: JsonObject
2327

2428
def asJson: Json = jsonObject.asJson
@@ -30,8 +34,16 @@ trait JsonSchema[A] extends JsonSchema.HasRef {
3034

3135
def asJsonRef: Json = asObjectRef.asJson
3236

33-
lazy val definition: JsonSchema.Definition =
34-
JsonSchema.Definition(id, relatedDefinitions.map(_.asRef), asJson)
37+
def namedDefinition(fieldName: String): NamedDefinition =
38+
JsonSchema.NamedDefinition(
39+
id,
40+
fieldName,
41+
relatedDefinitions.map(_.asRef),
42+
asJson
43+
)
44+
45+
lazy val definition: JsonSchema.UnnamedDefinition =
46+
JsonSchema.UnnamedDefinition(id, relatedDefinitions.map(_.asRef), asJson)
3547

3648
def definitions: Set[JsonSchema.Definition] =
3749
relatedDefinitions + definition
@@ -49,27 +61,43 @@ object JsonSchema
4961
with derive.CoprodInstances {
5062
trait HasRef {
5163
def id: String
52-
def asRef: Ref = TypeRef(id)
53-
def asArrayRef: Ref = ArrayRef(id)
64+
def asRef: Ref = TypeRef(id, None)
65+
def asArrayRef: Ref = ArrayRef(id, None)
5466
}
5567

56-
case class Definition(id: String, relatedRefs: Set[Ref], json: Json)
57-
extends HasRef
68+
sealed trait Definition extends HasRef {
69+
def id: String
70+
def json: Json
71+
def relatedRefs: Set[Ref]
72+
}
73+
74+
case class UnnamedDefinition(id: String, relatedRefs: Set[Ref], json: Json)
75+
extends Definition
76+
77+
case class NamedDefinition(id: String,
78+
fieldName: String,
79+
relatedRefs: Set[Ref],
80+
json: Json)
81+
extends Definition {
82+
override def asRef = TypeRef(id, Some(fieldName))
83+
override def asArrayRef = ArrayRef(id, Some(fieldName))
84+
}
5885

5986
sealed trait Ref {
6087
def id: String
88+
def fieldName: Option[String]
6189
}
6290

63-
case class TypeRef(id: String) extends Ref
91+
case class TypeRef(id: String, fieldName: Option[String]) extends Ref
6492
object TypeRef {
65-
def apply(definition: Definition): TypeRef = TypeRef(definition.id)
66-
def apply(schema: JsonSchema[_]): TypeRef = TypeRef(schema.id)
93+
def apply(definition: Definition): TypeRef = TypeRef(definition.id, None)
94+
def apply(schema: JsonSchema[_]): TypeRef = TypeRef(schema.id, None)
6795
}
6896

69-
case class ArrayRef(id: String) extends Ref
97+
case class ArrayRef(id: String, fieldName: Option[String]) extends Ref
7098
object ArrayRef {
71-
def apply(definition: Definition): ArrayRef = ArrayRef(definition.id)
72-
def apply(schema: JsonSchema[_]): ArrayRef = ArrayRef(schema.id)
99+
def apply(definition: Definition): ArrayRef = ArrayRef(definition.id, None)
100+
def apply(schema: JsonSchema[_]): ArrayRef = ArrayRef(schema.id, None)
73101
}
74102

75103
trait PatternProperty[K] {

src/main/scala/com/timeout/docless/schema/derive/HListInstances.scala

+6-4
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@ trait HListInstances {
1818
lazyHSchema: Lazy[JsonSchema[H]],
1919
lazyTSchema: Lazy[JsonSchema[T]]
2020
): JsonSchema[FieldType[K, H] :: T] = instanceAndRelated {
21-
val hSchema = lazyHSchema.value
22-
val tSchema = lazyTSchema.value
21+
val fieldName = witness.value.name
22+
val hSchema = lazyHSchema.value
23+
val tSchema = lazyTSchema.value
2324
val (hValue, related) =
2425
if (hSchema.inline)
2526
hSchema.asJson -> tSchema.relatedDefinitions
2627
else
27-
hSchema.asJsonRef -> (tSchema.relatedDefinitions + hSchema.definition)
28+
hSchema.asJsonRef -> (tSchema.relatedDefinitions + hSchema
29+
.namedDefinition(fieldName))
2830

29-
val hField = witness.value.name -> hValue
31+
val hField = fieldName -> hValue
3032
val tFields = tSchema.jsonObject.toList
3133

3234
JsonObject.fromIterable(hField :: tFields) -> related

src/main/scala/com/timeout/docless/swagger/PathGroup.scala

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ object PathGroup {
3333
val missingDefinitions =
3434
allDefs.foldMap { d =>
3535
d.relatedRefs.collect {
36-
case r @ TypeRef(id) if !definedIds.exists(_ === id) =>
36+
case r @ TypeRef(id, _) if !definedIds.exists(_ === id) =>
3737
SchemaError.missingDefinition(RefWithContext.definition(r, d))
3838
}
3939
}

src/main/scala/com/timeout/docless/swagger/SchemaError.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ object SchemaError {
1212

1313
implicit val mdShow: Show[SchemaError] = Show.show {
1414
case MissingDefinition(RefWithContext(r, DefinitionContext(d))) =>
15-
s"${d.id}: cannot find a field definition for: '${r.id}'"
15+
val fieldName = r.fieldName.fold("")(fld => s"(in field name: $fld)")
16+
s"${d.id}: cannot find a definition for '${r.id}' $fieldName"
1617
case MissingDefinition(RefWithContext(r, ParamContext(param, path))) =>
1718
s"$path: cannot find definition '${r.id}' for parameter name '$param'"
1819
case MissingDefinition(RefWithContext(r, ResponseContext(method, path))) =>

src/test/scala/com/timeout/docless/schema/JsonSchemaTest.scala

+9-9
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ class JsonSchemaTest extends FreeSpec {
111111
""".stripMargin) should ===(Right(schema.asJson))
112112

113113
schema.id should ===(id[Nested])
114-
schema.relatedDefinitions should ===(Set(fs.definition))
114+
schema.relatedDefinitions should ===(Set(fs.namedDefinition("foo")))
115115
}
116116

117117
"with types extending enumeratum.EnumEntry" - {
@@ -175,18 +175,18 @@ class JsonSchemaTest extends FreeSpec {
175175

176176
"provides JSON definitions of the coproduct" in {
177177
implicit val fs: JsonSchema[Foo] = fooSchema
178-
val schema = JsonSchema.deriveFor[ADT]
179-
val ySchema = JsonSchema.deriveFor[A]
180-
val zSchema = JsonSchema.deriveFor[B]
181178

182-
val z1Schema = JsonSchema.deriveFor[C]
179+
val schema = JsonSchema.deriveFor[ADT]
180+
val aSchema = JsonSchema.deriveFor[A]
181+
val bSchema = JsonSchema.deriveFor[B]
182+
val cSchema = JsonSchema.deriveFor[C]
183183

184184
schema.relatedDefinitions should ===(
185185
Set(
186-
ySchema.definition,
187-
zSchema.definition,
188-
z1Schema.definition,
189-
fooSchema.definition
186+
aSchema.definition,
187+
bSchema.definition,
188+
cSchema.definition,
189+
fooSchema.namedDefinition("foo")
190190
)
191191
)
192192
}

0 commit comments

Comments
 (0)