Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

openapi3filter: Include schema ref or title in response body validation errors #699

Merged
merged 11 commits into from Dec 14, 2022
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 the schema : field "Some field" must be an integer
}
3 changes: 2 additions & 1 deletion openapi3filter/validate_request.go
Expand Up @@ -273,10 +273,11 @@ 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)
return &RequestError{
Input: input,
RequestBody: requestBody,
Reason: "doesn't match the schema",
Reason: fmt.Sprintf("doesn't match the schema %s", schemaId),
slessard marked this conversation as resolved.
Show resolved Hide resolved
Err: err,
}
}
Expand Down
21 changes: 20 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,29 @@ 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)
return &ResponseError{
Input: input,
Reason: "response body doesn't match the schema",
Reason: fmt.Sprintf("response body doesn't match the schema %s", schemaId),
slessard marked this conversation as resolved.
Show resolved Hide resolved
Err: err,
// TODO: add an error message customizer function similar to SchemaError
slessard marked this conversation as resolved.
Show resolved Hide resolved
}
}
return nil
}

func getSchemaIdentifier(schema *openapi3.SchemaRef) string {
var id string

if schema != nil {
id = schema.Ref
}
if strings.TrimSpace(id) == "" && schema.Value != nil {
slessard marked this conversation as resolved.
Show resolved Hide resolved
id = schema.Value.Title
}
if strings.TrimSpace(id) == "" && schema.Value != nil {
id = schema.Value.Description
slessard marked this conversation as resolved.
Show resolved Hide resolved
}

return id
}
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 the 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 the 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 the 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 the 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 the 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 the 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 the 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 the schema : input matches more than one oneOf schemas

}