Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions openapi3/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,13 @@ func (meo multiErrorForOneOf) Error() string {
func (meo multiErrorForOneOf) Unwrap() error {
return MultiError(meo)
}

type multiErrorForAllOf MultiError

func (mea multiErrorForAllOf) Error() string {
return spliceErr(" And ", mea)
}

func (mea multiErrorForAllOf) Unwrap() error {
return MultiError(mea)
}
20 changes: 12 additions & 8 deletions openapi3/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -1429,6 +1429,7 @@ func (schema *Schema) visitXOFOperations(settings *schemaValidationSettings, val
visitedAnyOf = true
}

validationErrors := multiErrorForAllOf{}
for _, item := range schema.AllOf {
v := item.Value
if v == nil {
Expand All @@ -1438,17 +1439,20 @@ func (schema *Schema) visitXOFOperations(settings *schemaValidationSettings, val
if settings.failfast {
return errSchema, false
}
return &SchemaError{
Value: value,
Schema: schema,
SchemaField: "allOf",
Reason: `doesn't match all schemas from "allOf"`,
Origin: err,
customizeMessageError: settings.customizeMessageError,
}, false
validationErrors = append(validationErrors, err)
}
visitedAllOf = true
}
if len(validationErrors) > 0 {
return &SchemaError{
Value: value,
Schema: schema,
SchemaField: "allOf",
Reason: `doesn't match all schemas from "allOf"`,
Origin: fmt.Errorf("doesn't match schema due to: %w", validationErrors),
customizeMessageError: settings.customizeMessageError,
}, false
}

run = !((visitedOneOf || visitedAnyOf || visitedAllOf) && value == nil)
return
Expand Down
2 changes: 1 addition & 1 deletion openapi3filter/issue641_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ paths:
name: "failed allof pattern",
spec: allOfSpec,
req: `/items?test=999999`,
errStr: `parameter "test" in query has an error: string doesn't match the regular expression "^[0-9]{1,4}$"`,
errStr: `parameter "test" in query has an error: doesn't match schema due to: string doesn't match the regular expression "^[0-9]{1,4}$"`,
},
}

Expand Down
2 changes: 1 addition & 1 deletion openapi3filter/issue789_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ paths:
name: "failed allof object array",
spec: allOfArraySpec,
req: `/items?test=foo`,
errStr: `parameter "test" in query has an error: string doesn't match the regular expression`,
errStr: `parameter "test" in query has an error: doesn't match schema due to: string doesn't match the regular expression`,
},
{
name: "success oneof string pattern match",
Expand Down
60 changes: 51 additions & 9 deletions openapi3filter/validation_error_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package openapi3filter
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -47,6 +48,9 @@ type validationTest struct {
wantErrSchemaOriginReason string
wantErrSchemaOriginPath string
wantErrSchemaOriginValue any
wantMultiErrSchemaReasons []string
wantMultiErrSchemaPaths []string
wantMultiErrSchemaValues []any
wantErrParam string
wantErrParamIn string
wantErrParseKind ParseErrorKind
Expand Down Expand Up @@ -478,17 +482,38 @@ func getValidationTests(t *testing.T) []*validationTest {
args: validationArgs{
r: newPetstoreRequest(t, http.MethodPost, "/pet2", bytes.NewBufferString(`{"name":"Bahama"}`)),
},
wantErrReason: "doesn't match schema",
wantErrSchemaPath: "/",
wantErrSchemaValue: map[string]string{"name": "Bahama"},
wantErrSchemaReason: `doesn't match all schemas from "allOf"`,
wantErrSchemaOriginReason: `property "photoUrls" is missing`,
wantErrSchemaOriginValue: map[string]string{"name": "Bahama"},
wantErrSchemaOriginPath: "/photoUrls",
wantErrReason: "doesn't match schema",
wantErrSchemaPath: "/",
wantErrSchemaValue: map[string]string{"name": "Bahama"},
wantErrSchemaReason: `doesn't match all schemas from "allOf"`,
wantMultiErrSchemaPaths: []string{"/photoUrls"},
wantMultiErrSchemaValues: []any{map[string]string{"name": "Bahama"}},
wantMultiErrSchemaReasons: []string{
`property "photoUrls" is missing`,
},
wantErrResponse: &ValidationError{
Status: http.StatusUnprocessableEntity,
Title: `property "photoUrls" is missing`,
Source: &ValidationErrorSource{Pointer: "/photoUrls"},
Title: `doesn't match all schemas from "allOf"`,
},
},
{
name: "error - missing required object attribute and bad type from allOf required overlay",
args: validationArgs{
r: newPetstoreRequest(t, http.MethodPost, "/pet2", bytes.NewBufferString(`{"name":1}`)),
},
wantErrReason: "doesn't match schema",
wantErrSchemaPath: "/",
wantErrSchemaValue: map[string]float64{"name": 1},
wantErrSchemaReason: `doesn't match all schemas from "allOf"`,
wantMultiErrSchemaPaths: []string{"/name", "/photoUrls"},
wantMultiErrSchemaValues: []any{1, map[string]float64{"name": 1}},
wantMultiErrSchemaReasons: []string{
"value must be a string",
"property \"photoUrls\" is missing",
},
wantErrResponse: &ValidationError{
Status: http.StatusUnprocessableEntity,
Title: `doesn't match all schemas from "allOf"`,
},
},
{
Expand Down Expand Up @@ -599,6 +624,23 @@ func TestValidationHandler_validateRequest(t *testing.T) {
pointer := toJSONPointer(originErr.JSONPointer())
req.Equal(tt.wantErrSchemaOriginPath, pointer)
req.Equal(fmt.Sprint(tt.wantErrSchemaOriginValue), fmt.Sprint(originErr.Value))
} else if wrapErr := errors.Unwrap(innerErr.Origin); wrapErr != nil {
if multiErr, ok := errors.Unwrap(wrapErr).(openapi3.MultiError); ok {
req.Len(multiErr, len(tt.wantMultiErrSchemaReasons))
req.Len(multiErr, len(tt.wantMultiErrSchemaPaths))
req.Len(multiErr, len(tt.wantMultiErrSchemaValues))
for i, merr := range multiErr {
schemaErr, ok := merr.(*openapi3.SchemaError)
if !ok {
continue
}
req.Equal(tt.wantMultiErrSchemaReasons[i], schemaErr.Reason)
pointer := toJSONPointer(schemaErr.JSONPointer())
req.Equal(tt.wantMultiErrSchemaPaths[i], pointer)
req.Equal(fmt.Sprint(tt.wantMultiErrSchemaValues[i]), fmt.Sprint(schemaErr.Value))

}
}
}
} else {
req.False(tt.wantErrSchemaReason != "" || tt.wantErrSchemaPath != "",
Expand Down
Loading