From 98be931b17b48927fd35b66b9b3560c9c5918219 Mon Sep 17 00:00:00 2001 From: Greg Ward Date: Mon, 19 Dec 2022 09:24:06 -0500 Subject: [PATCH] feat: improve error reporting for bad/missing discriminator First, the error messages themselves are better: they give the name of the discriminator property itself, which gives the reader a clue where the problem lies. And they give the invalid value when there is one. Second, using SchemaError rather than errors.New() makes it possible for downstream interpreters to add more value to the error. --- openapi3/schema.go | 25 ++++++++++++++++++++++--- openapi3/schema_oneOf_test.go | 8 ++++---- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/openapi3/schema.go b/openapi3/schema.go index f2b4ea2c8..20c1fa550 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -922,16 +922,35 @@ func (schema *Schema) visitSetOperations(settings *schemaValidationSettings, val if valuemap, okcheck := value.(map[string]interface{}); okcheck { discriminatorVal, okcheck := valuemap[pn] if !okcheck { - return errors.New("input does not contain the discriminator property") + return &SchemaError{ + Schema: schema, + SchemaField: "discriminator", + Reason: fmt.Sprintf("input does not contain the discriminator property %q", pn), + } } discriminatorValString, okcheck := discriminatorVal.(string) if !okcheck { - return errors.New("descriminator value is not a string") + valStr := "null" + if discriminatorVal != nil { + valStr = fmt.Sprintf("%v", discriminatorVal) + } + + return &SchemaError{ + Value: discriminatorVal, + Schema: schema, + SchemaField: "discriminator", + Reason: fmt.Sprintf("value of discriminator property %q is not a string: %v", pn, valStr), + } } if discriminatorRef, okcheck = schema.Discriminator.Mapping[discriminatorValString]; len(schema.Discriminator.Mapping) > 0 && !okcheck { - return errors.New("input does not contain a valid discriminator value") + return &SchemaError{ + Value: discriminatorVal, + Schema: schema, + SchemaField: "discriminator", + Reason: fmt.Sprintf("discriminator property %q has invalid value: %q", pn, discriminatorVal), + } } } } diff --git a/openapi3/schema_oneOf_test.go b/openapi3/schema_oneOf_test.go index d3e689d51..1a8ea8138 100644 --- a/openapi3/schema_oneOf_test.go +++ b/openapi3/schema_oneOf_test.go @@ -86,7 +86,7 @@ func TestVisitJSON_OneOf_MissingDiscriptorProperty(t *testing.T) { err = s.Components.Schemas["Animal"].Value.VisitJSON(map[string]interface{}{ "name": "snoopy", }) - require.EqualError(t, err, "input does not contain the discriminator property") + require.ErrorContains(t, err, "input does not contain the discriminator property \"$type\"\n") } func TestVisitJSON_OneOf_MissingDiscriptorValue(t *testing.T) { @@ -96,7 +96,7 @@ func TestVisitJSON_OneOf_MissingDiscriptorValue(t *testing.T) { "name": "snoopy", "$type": "snake", }) - require.EqualError(t, err, "input does not contain a valid discriminator value") + require.ErrorContains(t, err, "discriminator property \"$type\" has invalid value: \"snake\"") } func TestVisitJSON_OneOf_MissingField(t *testing.T) { @@ -126,14 +126,14 @@ func TestVisitJSON_OneOf_BadDescriminatorType(t *testing.T) { "scratches": true, "$type": 1, }) - require.EqualError(t, err, "descriminator value is not a string") + require.ErrorContains(t, err, "value of discriminator property \"$type\" is not a string: 1") err = s.Components.Schemas["Animal"].Value.VisitJSON(map[string]interface{}{ "name": "snoopy", "barks": true, "$type": nil, }) - require.EqualError(t, err, "descriminator value is not a string") + require.ErrorContains(t, err, "value of discriminator property \"$type\" is not a string: null") } func TestVisitJSON_OneOf_Path(t *testing.T) {