Skip to content

Commit

Permalink
openapi3filter: Include schema ref or title in response body validati…
Browse files Browse the repository at this point in the history
…on errors (#699)

Co-authored-by: Steve Lessard <steve.lessard@teradata.com>
  • Loading branch information
slessard and Steve Lessard committed Dec 14, 2022
1 parent b003421 commit 7413c27
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 11 deletions.
2 changes: 1 addition & 1 deletion openapi3filter/options_test.go
Expand Up @@ -78,5 +78,5 @@ paths:

fmt.Println(err.Error())

// Output: request body has an error: doesn't match the schema: field "Some field" must be an integer
// Output: request body has an error: doesn't match schema: field "Some field" must be an integer
}
4 changes: 3 additions & 1 deletion openapi3filter/validate_request.go
Expand Up @@ -286,10 +286,12 @@ func ValidateRequestBody(ctx context.Context, input *RequestValidationInput, req

// Validate JSON with the schema
if err := contentType.Schema.Value.VisitJSON(value, opts...); err != nil {
schemaId := getSchemaIdentifier(contentType.Schema)
schemaId = prependSpaceIfNeeded(schemaId)
return &RequestError{
Input: input,
RequestBody: requestBody,
Reason: "doesn't match the schema",
Reason: fmt.Sprintf("doesn't match schema%s", schemaId),
Err: err,
}
}
Expand Down
28 changes: 27 additions & 1 deletion openapi3filter/validate_response.go
Expand Up @@ -8,6 +8,7 @@ import (
"io/ioutil"
"net/http"
"sort"
"strings"

"github.com/getkin/kin-openapi/openapi3"
)
Expand Down Expand Up @@ -159,11 +160,36 @@ func ValidateResponse(ctx context.Context, input *ResponseValidationInput) error

// Validate data with the schema.
if err := contentType.Schema.Value.VisitJSON(value, append(opts, openapi3.VisitAsResponse())...); err != nil {
schemaId := getSchemaIdentifier(contentType.Schema)
schemaId = prependSpaceIfNeeded(schemaId)
return &ResponseError{
Input: input,
Reason: "response body doesn't match the schema",
Reason: fmt.Sprintf("response body doesn't match schema%s", schemaId),
Err: err,
}
}
return nil
}

// getSchemaIdentifier gets something by which a schema could be identified.
// A schema by itself doesn't have a true identity field. This function makes
// a best effort to get a value that can fill that void.
func getSchemaIdentifier(schema *openapi3.SchemaRef) string {
var id string

if schema != nil {
id = strings.TrimSpace(schema.Ref)
}
if id == "" && schema.Value != nil {
id = strings.TrimSpace(schema.Value.Title)
}

return id
}

func prependSpaceIfNeeded(value string) string {
if len(value) > 0 {
value = " " + value
}
return value
}
12 changes: 6 additions & 6 deletions openapi3filter/validation_error_test.go
Expand Up @@ -322,7 +322,7 @@ func getValidationTests(t *testing.T) []*validationTest {
args: validationArgs{
r: newPetstoreRequest(t, http.MethodPost, "/pet", bytes.NewBufferString(`{"status":"watdis"}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema #/components/schemas/PetWithRequired",
wantErrSchemaReason: "value \"watdis\" is not one of the allowed values",
wantErrSchemaValue: "watdis",
wantErrSchemaPath: "/status",
Expand All @@ -336,7 +336,7 @@ func getValidationTests(t *testing.T) []*validationTest {
args: validationArgs{
r: newPetstoreRequest(t, http.MethodPost, "/pet", bytes.NewBufferString(`{"name":"Bahama"}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema #/components/schemas/PetWithRequired",
wantErrSchemaReason: `property "photoUrls" is missing`,
wantErrSchemaValue: map[string]string{"name": "Bahama"},
wantErrSchemaPath: "/photoUrls",
Expand All @@ -350,7 +350,7 @@ func getValidationTests(t *testing.T) []*validationTest {
r: newPetstoreRequest(t, http.MethodPost, "/pet",
bytes.NewBufferString(`{"name":"Bahama","photoUrls":[],"category":{}}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema #/components/schemas/PetWithRequired",
wantErrSchemaReason: `property "name" is missing`,
wantErrSchemaValue: map[string]string{},
wantErrSchemaPath: "/category/name",
Expand All @@ -364,7 +364,7 @@ func getValidationTests(t *testing.T) []*validationTest {
r: newPetstoreRequest(t, http.MethodPost, "/pet",
bytes.NewBufferString(`{"name":"Bahama","photoUrls":[],"category":{"tags": [{}]}}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema #/components/schemas/PetWithRequired",
wantErrSchemaReason: `property "name" is missing`,
wantErrSchemaValue: map[string]string{},
wantErrSchemaPath: "/category/tags/0/name",
Expand All @@ -378,7 +378,7 @@ func getValidationTests(t *testing.T) []*validationTest {
r: newPetstoreRequest(t, http.MethodPost, "/pet",
bytes.NewBufferString(`{"name":"Bahama","photoUrls":"http://cat"}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema #/components/schemas/PetWithRequired",
wantErrSchemaReason: "field must be set to array or not be present",
wantErrSchemaPath: "/photoUrls",
wantErrSchemaValue: "string",
Expand All @@ -393,7 +393,7 @@ func getValidationTests(t *testing.T) []*validationTest {
args: validationArgs{
r: newPetstoreRequest(t, http.MethodPost, "/pet2", bytes.NewBufferString(`{"name":"Bahama"}`)),
},
wantErrReason: "doesn't match the schema",
wantErrReason: "doesn't match schema",
wantErrSchemaPath: "/",
wantErrSchemaValue: map[string]string{"name": "Bahama"},
wantErrSchemaOriginReason: `property "photoUrls" is missing`,
Expand Down
2 changes: 1 addition & 1 deletion routers/gorillamux/example_test.go
Expand Up @@ -53,7 +53,7 @@ func Example() {
err = openapi3filter.ValidateResponse(ctx, responseValidationInput)
fmt.Println(err)
// Output:
// response body doesn't match the schema: field must be set to string or not be present
// response body doesn't match schema pathref.openapi.yml#/components/schemas/TestSchema: field must be set to string or not be present
// Schema:
// {
// "type": "string"
Expand Down
2 changes: 1 addition & 1 deletion routers/legacy/validate_request_test.go
Expand Up @@ -107,6 +107,6 @@ func Example() {
fmt.Println(err)
}
// Output:
// request body has an error: doesn't match the schema: input matches more than one oneOf schemas
// request body has an error: doesn't match schema: input matches more than one oneOf schemas

}

0 comments on commit 7413c27

Please sign in to comment.