diff --git a/errors/parameter_errors.go b/errors/parameter_errors.go index 2f9768a4..9bbcee85 100644 --- a/errors/parameter_errors.go +++ b/errors/parameter_errors.go @@ -76,7 +76,12 @@ func InvalidDeepObject(param *v3.Parameter, qp *helpers.QueryParam) *ValidationE } } -func QueryParameterMissing(param *v3.Parameter) *ValidationError { +func QueryParameterMissing(param *v3.Parameter, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/required", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -86,10 +91,23 @@ func QueryParameterMissing(param *v3.Parameter) *ValidationError { SpecLine: param.GoLow().Required.KeyNode.Line, SpecCol: param.GoLow().Required.KeyNode.Column, HowToFix: HowToFixMissingValue, + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Required query parameter '%s' is missing", param.Name), + FieldName: param.Name, + FieldPath: "", + InstancePath: []string{}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func HeaderParameterMissing(param *v3.Parameter) *ValidationError { +func HeaderParameterMissing(param *v3.Parameter, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/required", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -99,10 +117,23 @@ func HeaderParameterMissing(param *v3.Parameter) *ValidationError { SpecLine: param.GoLow().Required.KeyNode.Line, SpecCol: param.GoLow().Required.KeyNode.Column, HowToFix: HowToFixMissingValue, + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Required header parameter '%s' is missing", param.Name), + FieldName: param.Name, + FieldPath: "", + InstancePath: []string{}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func HeaderParameterCannotBeDecoded(param *v3.Parameter, val string) *ValidationError { +func HeaderParameterCannotBeDecoded(param *v3.Parameter, val string, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -112,15 +143,28 @@ func HeaderParameterCannotBeDecoded(param *v3.Parameter, val string) *Validation SpecLine: param.GoLow().Schema.Value.Schema().Type.KeyNode.Line, SpecCol: param.GoLow().Schema.Value.Schema().Type.KeyNode.Line, HowToFix: HowToFixInvalidEncoding, + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Header value '%s' cannot be decoded as object (malformed encoding)", val), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectHeaderParamEnum(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectHeaderParamEnum(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { var enums []string for i := range sch.Enum { enums = append(enums, fmt.Sprint(sch.Enum[i].Value)) } validEnums := strings.Join(enums, ", ") + + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/enum", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -131,12 +175,24 @@ func IncorrectHeaderParamEnum(param *v3.Parameter, ef string, sch *base.Schema) SpecCol: param.GoLow().Schema.Value.Schema().Enum.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidEnum, ef, validEnums), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' does not match any enum values: [%s]", ef, validEnums), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectQueryParamArrayBoolean( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -147,10 +203,22 @@ func IncorrectQueryParamArrayBoolean( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid boolean", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } -func IncorrectParamArrayMaxNumItems(param *v3.Parameter, sch *base.Schema, expected, actual int64) *ValidationError { +func IncorrectParamArrayMaxNumItems(param *v3.Parameter, sch *base.Schema, expected, actual int64, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/maxItems", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -161,10 +229,22 @@ func IncorrectParamArrayMaxNumItems(param *v3.Parameter, sch *base.Schema, expec SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixInvalidMaxItems, expected), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array has %d items, but maximum is %d", actual, expected), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectParamArrayMinNumItems(param *v3.Parameter, sch *base.Schema, expected, actual int64) *ValidationError { +func IncorrectParamArrayMinNumItems(param *v3.Parameter, sch *base.Schema, expected, actual int64, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/minItems", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -175,10 +255,22 @@ func IncorrectParamArrayMinNumItems(param *v3.Parameter, sch *base.Schema, expec SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixInvalidMinItems, expected), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array has %d items, but minimum is %d", actual, expected), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectParamArrayUniqueItems(param *v3.Parameter, sch *base.Schema, duplicates string) *ValidationError { +func IncorrectParamArrayUniqueItems(param *v3.Parameter, sch *base.Schema, duplicates string, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/uniqueItems", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -188,12 +280,24 @@ func IncorrectParamArrayUniqueItems(param *v3.Parameter, sch *base.Schema, dupli SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: sch, HowToFix: "Ensure the array values are all unique", + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array contains duplicate values: %s", duplicates), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectCookieParamArrayBoolean( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -204,12 +308,24 @@ func IncorrectCookieParamArrayBoolean( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid boolean", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } func IncorrectQueryParamArrayInteger( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -220,12 +336,24 @@ func IncorrectQueryParamArrayInteger( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidInteger, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid integer", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } func IncorrectQueryParamArrayNumber( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -236,12 +364,24 @@ func IncorrectQueryParamArrayNumber( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid number", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } func IncorrectCookieParamArrayNumber( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -252,10 +392,22 @@ func IncorrectCookieParamArrayNumber( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid number", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } -func IncorrectParamEncodingJSON(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectParamEncodingJSON(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/content/application~1json/schema", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -266,10 +418,22 @@ func IncorrectParamEncodingJSON(param *v3.Parameter, ef string, sch *base.Schema SpecCol: param.GoLow().FindContent(helpers.JSONContentType).ValueNode.Column, Context: sch, HowToFix: HowToFixInvalidJSON, + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not valid JSON", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectQueryParamBool(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectQueryParamBool(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -281,10 +445,22 @@ func IncorrectQueryParamBool(param *v3.Parameter, ef string, sch *base.Schema) * ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid boolean", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidQueryParamInteger(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidQueryParamInteger(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -296,10 +472,22 @@ func InvalidQueryParamInteger(param *v3.Parameter, ef string, sch *base.Schema) ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidInteger, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid integer", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidQueryParamNumber(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidQueryParamNumber(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -311,15 +499,28 @@ func InvalidQueryParamNumber(param *v3.Parameter, ef string, sch *base.Schema) * ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid number", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectQueryParamEnum(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectQueryParamEnum(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { var enums []string for i := range sch.Enum { enums = append(enums, fmt.Sprint(sch.Enum[i].Value)) } validEnums := strings.Join(enums, ", ") + + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/enum", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -331,10 +532,17 @@ func IncorrectQueryParamEnum(param *v3.Parameter, ef string, sch *base.Schema) * ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidEnum, ef, validEnums), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' does not match any enum values: [%s]", ef, validEnums), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectQueryParamEnumArray(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectQueryParamEnumArray(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedItemsSchema string) *ValidationError { var enums []string // look at that model fly! for i := range param.GoLow().Schema.Value.Schema().Items.Value.A.Schema().Enum.Value { @@ -342,6 +550,12 @@ func IncorrectQueryParamEnumArray(param *v3.Parameter, ef string, sch *base.Sche fmt.Sprint(param.GoLow().Schema.Value.Schema().Items.Value.A.Schema().Enum.Value[i].Value.Value)) } validEnums := strings.Join(enums, ", ") + + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/enum", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -352,10 +566,22 @@ func IncorrectQueryParamEnumArray(param *v3.Parameter, ef string, sch *base.Sche SpecCol: param.GoLow().Schema.Value.Schema().Items.Value.A.Schema().Enum.KeyNode.Line, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidEnum, ef, validEnums), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' does not match any enum values: [%s]", ef, validEnums), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } -func IncorrectReservedValues(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectReservedValues(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/allowReserved", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationQuery, @@ -366,10 +592,22 @@ func IncorrectReservedValues(param *v3.Parameter, ef string, sch *base.Schema) * SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixReservedValues, url.QueryEscape(ef)), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' contains reserved characters but allowReserved is false", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidHeaderParamInteger(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidHeaderParamInteger(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -381,10 +619,22 @@ func InvalidHeaderParamInteger(param *v3.Parameter, ef string, sch *base.Schema) ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidInteger, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid integer", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidHeaderParamNumber(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidHeaderParamNumber(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -396,10 +646,22 @@ func InvalidHeaderParamNumber(param *v3.Parameter, ef string, sch *base.Schema) ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid number", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidCookieParamInteger(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidCookieParamInteger(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -410,10 +672,22 @@ func InvalidCookieParamInteger(param *v3.Parameter, ef string, sch *base.Schema) SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidInteger, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid integer", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func InvalidCookieParamNumber(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func InvalidCookieParamNumber(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -424,10 +698,22 @@ func InvalidCookieParamNumber(param *v3.Parameter, ef string, sch *base.Schema) SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid number", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectHeaderParamBool(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectHeaderParamBool(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -439,10 +725,22 @@ func IncorrectHeaderParamBool(param *v3.Parameter, ef string, sch *base.Schema) ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid boolean", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectCookieParamBool(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectCookieParamBool(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -453,15 +751,28 @@ func IncorrectCookieParamBool(param *v3.Parameter, ef string, sch *base.Schema) SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, ef), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid boolean", ef), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectCookieParamEnum(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectCookieParamEnum(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, operation string, renderedSchema string) *ValidationError { var enums []string for i := range sch.Enum { enums = append(enums, fmt.Sprint(sch.Enum[i].Value)) } validEnums := strings.Join(enums, ", ") + + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/enum", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationCookie, @@ -472,12 +783,24 @@ func IncorrectCookieParamEnum(param *v3.Parameter, ef string, sch *base.Schema) SpecCol: param.GoLow().Schema.Value.Schema().Enum.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidEnum, ef, validEnums), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' does not match any enum values: [%s]", ef, validEnums), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectHeaderParamArrayBoolean( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -488,12 +811,24 @@ func IncorrectHeaderParamArrayBoolean( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid boolean", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } func IncorrectHeaderParamArrayNumber( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, operation string, renderedItemsSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") + keywordLocation := fmt.Sprintf("/paths/%s/%s/parameters/%s/schema/items/type", escapedPath, strings.ToLower(operation), param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationHeader, @@ -504,10 +839,21 @@ func IncorrectHeaderParamArrayNumber( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid number", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedItemsSchema, + }}, } } -func IncorrectPathParamBool(param *v3.Parameter, item string, sch *base.Schema) *ValidationError { +func IncorrectPathParamBool(param *v3.Parameter, item string, sch *base.Schema, pathTemplate string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -518,15 +864,27 @@ func IncorrectPathParamBool(param *v3.Parameter, item string, sch *base.Schema) SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid boolean", item), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectPathParamEnum(param *v3.Parameter, ef string, sch *base.Schema) *ValidationError { +func IncorrectPathParamEnum(param *v3.Parameter, ef string, sch *base.Schema, pathTemplate string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/enum", escapedPath, param.Name) + var enums []string for i := range sch.Enum { enums = append(enums, fmt.Sprint(sch.Enum[i].Value)) } validEnums := strings.Join(enums, ", ") + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -537,10 +895,21 @@ func IncorrectPathParamEnum(param *v3.Parameter, ef string, sch *base.Schema) *V SpecCol: param.GoLow().Schema.Value.Schema().Enum.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidEnum, ef, validEnums), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' does not match any enum values: [%s]", ef, validEnums), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectPathParamInteger(param *v3.Parameter, item string, sch *base.Schema) *ValidationError { +func IncorrectPathParamInteger(param *v3.Parameter, item string, sch *base.Schema, pathTemplate string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -552,10 +921,21 @@ func IncorrectPathParamInteger(param *v3.Parameter, item string, sch *base.Schem ParameterName: param.Name, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidInteger, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid integer", item), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func IncorrectPathParamNumber(param *v3.Parameter, item string, sch *base.Schema) *ValidationError { +func IncorrectPathParamNumber(param *v3.Parameter, item string, sch *base.Schema, pathTemplate string, renderedSchema string) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -566,12 +946,23 @@ func IncorrectPathParamNumber(param *v3.Parameter, item string, sch *base.Schema SpecCol: param.GoLow().Schema.KeyNode.Column, Context: sch, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Value '%s' is not a valid number", item), + FieldName: param.Name, + InstancePath: []string{param.Name}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectPathParamArrayNumber( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, renderedSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/items/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -582,12 +973,23 @@ func IncorrectPathParamArrayNumber( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid number", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectPathParamArrayInteger( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, renderedSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/items/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -598,12 +1000,23 @@ func IncorrectPathParamArrayInteger( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidNumber, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid integer", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } func IncorrectPathParamArrayBoolean( - param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, + param *v3.Parameter, item string, sch *base.Schema, itemsSchema *base.Schema, pathTemplate string, renderedSchema string, ) *ValidationError { + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + keywordLocation := fmt.Sprintf("/paths/%s/parameters/%s/schema/items/type", escapedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -614,10 +1027,24 @@ func IncorrectPathParamArrayBoolean( SpecCol: sch.Items.A.GoLow().Schema().Type.KeyNode.Column, Context: itemsSchema, HowToFix: fmt.Sprintf(HowToFixParamInvalidBoolean, item), + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Array item '%s' is not a valid boolean", item), + FieldName: param.Name, + InstancePath: []string{param.Name, "[item]"}, + KeywordLocation: keywordLocation, + ReferenceSchema: renderedSchema, + }}, } } -func PathParameterMissing(param *v3.Parameter) *ValidationError { +func PathParameterMissing(param *v3.Parameter, pathTemplate string, actualPath string) *ValidationError { + actualSegments := strings.Split(strings.Trim(actualPath, "/"), "/") + + encodedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + encodedPath = strings.ReplaceAll(encodedPath, "/", "~1") + encodedPath = strings.TrimPrefix(encodedPath, "~1") + keywordLoc := fmt.Sprintf("/paths/%s/parameters/%s/required", encodedPath, param.Name) + return &ValidationError{ ValidationType: helpers.ParameterValidation, ValidationSubType: helpers.ParameterValidationPath, @@ -627,5 +1054,12 @@ func PathParameterMissing(param *v3.Parameter) *ValidationError { SpecLine: param.GoLow().Required.KeyNode.Line, SpecCol: param.GoLow().Required.KeyNode.Column, HowToFix: HowToFixMissingValue, + SchemaValidationErrors: []*SchemaValidationFailure{{ + Reason: fmt.Sprintf("Required path parameter '%s' is missing from path '%s'", param.Name, actualPath), + FieldName: param.Name, + FieldPath: "", + InstancePath: actualSegments, + KeywordLocation: keywordLoc, + }}, } } diff --git a/errors/parameter_errors_test.go b/errors/parameter_errors_test.go index 4f8304a6..4fb5b9b6 100644 --- a/errors/parameter_errors_test.go +++ b/errors/parameter_errors_test.go @@ -119,7 +119,7 @@ func TestQueryParameterMissing(t *testing.T) { param := createMockParameterWithSchema() // Call the function - err := QueryParameterMissing(param) + err := QueryParameterMissing(param, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -134,7 +134,7 @@ func TestHeaderParameterMissing(t *testing.T) { param := createMockParameterWithSchema() // Call the function - err := HeaderParameterMissing(param) + err := HeaderParameterMissing(param, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -150,7 +150,7 @@ func TestHeaderParameterCannotBeDecoded(t *testing.T) { val := "malformed_header_value" // Call the function - err := HeaderParameterCannotBeDecoded(param, val) + err := HeaderParameterCannotBeDecoded(param, val, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -187,7 +187,7 @@ func TestIncorrectHeaderParamEnum(t *testing.T) { schema := base.NewSchema(s) // Call the function with an invalid enum value - err := IncorrectHeaderParamEnum(param, "invalidEnum", schema) + err := IncorrectHeaderParamEnum(param, "invalidEnum", schema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -223,7 +223,7 @@ func TestIncorrectQueryParamArrayBoolean(t *testing.T) { schema := base.NewSchema(s) // Call the function with an invalid boolean value in the array - err := IncorrectQueryParamArrayBoolean(param, "notBoolean", schema, schema.Items.A.Schema()) + err := IncorrectQueryParamArrayBoolean(param, "notBoolean", schema, schema.Items.A.Schema(), "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -314,7 +314,7 @@ func TestIncorrectCookieParamArrayBoolean(t *testing.T) { itemsSchema := base.NewSchema(baseSchema.Items.Value.A.Schema()) // Call the function with an invalid boolean value in the array - err := IncorrectCookieParamArrayBoolean(param, "notBoolean", s, itemsSchema) + err := IncorrectCookieParamArrayBoolean(param, "notBoolean", s, itemsSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -375,7 +375,7 @@ func TestIncorrectQueryParamArrayInteger(t *testing.T) { itemsSchema := base.NewSchema(baseSchema.Items.Value.A.Schema()) // Call the function with an invalid number value in the array - err := IncorrectQueryParamArrayInteger(param, "notNumber", s, itemsSchema) + err := IncorrectQueryParamArrayInteger(param, "notNumber", s, itemsSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -394,7 +394,7 @@ func TestIncorrectQueryParamArrayNumber(t *testing.T) { itemsSchema := base.NewSchema(baseSchema.Items.Value.A.Schema()) // Call the function with an invalid number value in the array - err := IncorrectQueryParamArrayNumber(param, "notNumber", s, itemsSchema) + err := IncorrectQueryParamArrayNumber(param, "notNumber", s, itemsSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -455,7 +455,7 @@ func TestIncorrectCookieParamArrayNumber(t *testing.T) { itemsSchema := base.NewSchema(baseSchema.Items.Value.A.Schema()) // Call the function with an invalid number value in the cookie array - err := IncorrectCookieParamArrayNumber(param, "notNumber", s, itemsSchema) + err := IncorrectCookieParamArrayNumber(param, "notNumber", s, itemsSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -531,7 +531,7 @@ func TestIncorrectParamEncodingJSON(t *testing.T) { baseSchema := createMockLowBaseSchema() // Call the function with an invalid JSON value - err := IncorrectParamEncodingJSON(param, "invalidJSON", base.NewSchema(baseSchema)) + err := IncorrectParamEncodingJSON(param, "invalidJSON", base.NewSchema(baseSchema), "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -560,7 +560,7 @@ func TestIncorrectQueryParamBool(t *testing.T) { }) // Call the function with an invalid boolean value - err := IncorrectQueryParamBool(param, "notBoolean", base.NewSchema(baseSchema)) + err := IncorrectQueryParamBool(param, "notBoolean", base.NewSchema(baseSchema), "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -576,7 +576,7 @@ func TestInvalidQueryParamNumber(t *testing.T) { baseSchema := createMockLowBaseSchema() // Call the function with an invalid number value - err := InvalidQueryParamNumber(param, "notNumber", base.NewSchema(baseSchema)) + err := InvalidQueryParamNumber(param, "notNumber", base.NewSchema(baseSchema), "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -592,7 +592,7 @@ func TestInvalidQueryParamInteger(t *testing.T) { baseSchema := createMockLowBaseSchema() // Call the function with an invalid number value - err := InvalidQueryParamInteger(param, "notNumber", base.NewSchema(baseSchema)) + err := InvalidQueryParamInteger(param, "notNumber", base.NewSchema(baseSchema), "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -617,7 +617,7 @@ func TestIncorrectQueryParamEnum(t *testing.T) { param.GoLow().Schema.Value.Schema().Enum.KeyNode = &yaml.Node{} // Call the function with an invalid enum value - err := IncorrectQueryParamEnum(param, "invalidEnum", highSchema) + err := IncorrectQueryParamEnum(param, "invalidEnum", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -646,7 +646,7 @@ func TestIncorrectQueryParamEnumArray(t *testing.T) { } // Call the function with an invalid enum value - err := IncorrectQueryParamEnumArray(param, "invalidEnum", highSchema) + err := IncorrectQueryParamEnumArray(param, "invalidEnum", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -669,7 +669,7 @@ func TestIncorrectReservedValues(t *testing.T) { param := createMockParameter() param.Name = "borked::?^&*" - err := IncorrectReservedValues(param, "borked::?^&*", highSchema) + err := IncorrectReservedValues(param, "borked::?^&*", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -692,7 +692,7 @@ func TestInvalidHeaderParamInteger(t *testing.T) { param := createMockParameter() param.Name = "bunny" - err := InvalidHeaderParamInteger(param, "bunmy", highSchema) + err := InvalidHeaderParamInteger(param, "bunmy", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -715,7 +715,7 @@ func TestInvalidHeaderParamNumber(t *testing.T) { param := createMockParameter() param.Name = "bunny" - err := InvalidHeaderParamNumber(param, "bunmy", highSchema) + err := InvalidHeaderParamNumber(param, "bunmy", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -738,7 +738,7 @@ func TestInvalidCookieParamNumber(t *testing.T) { param := createMockParameter() param.Name = "cookies" - err := InvalidCookieParamNumber(param, "milky", highSchema) + err := InvalidCookieParamNumber(param, "milky", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -761,7 +761,7 @@ func TestInvalidCookieParamInteger(t *testing.T) { param := createMockParameter() param.Name = "cookies" - err := InvalidCookieParamInteger(param, "milky", highSchema) + err := InvalidCookieParamInteger(param, "milky", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -784,7 +784,7 @@ func TestIncorrectHeaderParamBool(t *testing.T) { param := createMockParameter() param.Name = "cookies" - err := IncorrectHeaderParamBool(param, "milky", highSchema) + err := IncorrectHeaderParamBool(param, "milky", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -807,7 +807,7 @@ func TestIncorrectCookieParamBool(t *testing.T) { param := createMockParameter() param.Name = "cookies" - err := IncorrectCookieParamBool(param, "milky", highSchema) + err := IncorrectCookieParamBool(param, "milky", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -837,7 +837,7 @@ items: } param.GoLow().Schema.Value.Schema().Enum.KeyNode = &yaml.Node{} - err := IncorrectCookieParamEnum(param, "milky", highSchema) + err := IncorrectCookieParamEnum(param, "milky", highSchema, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -863,7 +863,7 @@ func TestIncorrectHeaderParamArrayBoolean(t *testing.T) { param := createMockParameter() param.Name = "bubbles" - err := IncorrectHeaderParamArrayBoolean(param, "milky", highSchema, nil) + err := IncorrectHeaderParamArrayBoolean(param, "milky", highSchema, nil, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -889,7 +889,7 @@ func TestIncorrectHeaderParamArrayNumber(t *testing.T) { param := createMockParameter() param.Name = "bubbles" - err := IncorrectHeaderParamArrayNumber(param, "milky", highSchema, nil) + err := IncorrectHeaderParamArrayNumber(param, "milky", highSchema, nil, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -914,7 +914,7 @@ func TestIncorrectPathParamBool(t *testing.T) { param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectPathParamBool(param, "milky", highSchema) + err := IncorrectPathParamBool(param, "milky", highSchema, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -945,7 +945,7 @@ items: } param.GoLow().Schema.Value.Schema().Enum.KeyNode = &yaml.Node{} - err := IncorrectPathParamEnum(param, "milky", highSchema) + err := IncorrectPathParamEnum(param, "milky", highSchema, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -970,7 +970,7 @@ func TestIncorrectPathParamNumber(t *testing.T) { param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectPathParamNumber(param, "milky", highSchema) + err := IncorrectPathParamNumber(param, "milky", highSchema, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -995,7 +995,7 @@ func TestIncorrectPathParamInteger(t *testing.T) { param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectPathParamInteger(param, "milky", highSchema) + err := IncorrectPathParamInteger(param, "milky", highSchema, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -1021,7 +1021,7 @@ func TestIncorrectPathParamArrayNumber(t *testing.T) { param := createMockParameter() param.Name = "bubbles" - err := IncorrectPathParamArrayNumber(param, "milky", highSchema, nil) + err := IncorrectPathParamArrayNumber(param, "milky", highSchema, nil, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -1047,7 +1047,7 @@ func TestIncorrectPathParamArrayInteger(t *testing.T) { param := createMockParameter() param.Name = "bubbles" - err := IncorrectPathParamArrayInteger(param, "milky", highSchema, nil) + err := IncorrectPathParamArrayInteger(param, "milky", highSchema, nil, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -1073,7 +1073,7 @@ func TestIncorrectPathParamArrayBoolean(t *testing.T) { param := createMockParameter() param.Name = "bubbles" - err := IncorrectPathParamArrayBoolean(param, "milky", highSchema, nil) + err := IncorrectPathParamArrayBoolean(param, "milky", highSchema, nil, "/test-path", "{}") // Validate the error require.NotNil(t, err) @@ -1098,7 +1098,7 @@ func TestPathParameterMissing(t *testing.T) { param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := PathParameterMissing(param) + err := PathParameterMissing(param, "/test/{testQueryParam}", "/test/") // Validate the error require.NotNil(t, err) @@ -1124,7 +1124,7 @@ items: param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectParamArrayMaxNumItems(param, param.Schema.Schema(), 10, 25) + err := IncorrectParamArrayMaxNumItems(param, param.Schema.Schema(), 10, 25, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -1150,7 +1150,7 @@ items: param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectParamArrayMinNumItems(param, param.Schema.Schema(), 10, 5) + err := IncorrectParamArrayMinNumItems(param, param.Schema.Schema(), 10, 5, "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) @@ -1176,7 +1176,7 @@ items: param.Schema = base.CreateSchemaProxy(highSchema) param.GoLow().Schema.KeyNode = &yaml.Node{} - err := IncorrectParamArrayUniqueItems(param, param.Schema.Schema(), "fish, cake") + err := IncorrectParamArrayUniqueItems(param, param.Schema.Schema(), "fish, cake", "/test-path", "get", "{}") // Validate the error require.NotNil(t, err) diff --git a/parameters/cookie_parameters.go b/parameters/cookie_parameters.go index 8f74b9ff..cd85f443 100644 --- a/parameters/cookie_parameters.go +++ b/parameters/cookie_parameters.go @@ -4,6 +4,7 @@ package parameters import ( + "encoding/json" "fmt" "net/http" "strconv" @@ -43,6 +44,7 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, // extract params for the operation params := helpers.ExtractParamsForOperation(request, pathItem) var validationErrors []*errors.ValidationError + operation := strings.ToLower(request.Method) for _, p := range params { if p.In == helpers.Cookie { for _, cookie := range request.Cookies() { @@ -52,6 +54,15 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, if p.Schema != nil { sch = p.Schema.Schema() } + + // Render schema once for ReferenceSchema field in errors + var renderedSchema string + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + pType := sch.Type for _, ty := range pType { @@ -59,7 +70,7 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, case helpers.Integer: if _, err := strconv.ParseInt(cookie.Value, 10, 64); err != nil { validationErrors = append(validationErrors, - errors.InvalidCookieParamInteger(p, strings.ToLower(cookie.Value), sch)) + errors.InvalidCookieParamInteger(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) break } // check if enum is in range @@ -73,13 +84,13 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch)) + errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) } } case helpers.Number: if _, err := strconv.ParseFloat(cookie.Value, 64); err != nil { validationErrors = append(validationErrors, - errors.InvalidCookieParamNumber(p, strings.ToLower(cookie.Value), sch)) + errors.InvalidCookieParamNumber(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) break } // check if enum is in range @@ -93,13 +104,13 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch)) + errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) } } case helpers.Boolean: if _, err := strconv.ParseBool(cookie.Value); err != nil { validationErrors = append(validationErrors, - errors.IncorrectCookieParamBool(p, strings.ToLower(cookie.Value), sch)) + errors.IncorrectCookieParamBool(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) } case helpers.Object: if !p.IsExploded() { @@ -125,7 +136,7 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, // only check if items is a schema, not a boolean if sch.Items.IsA() { validationErrors = append(validationErrors, - ValidateCookieArray(sch, p, cookie.Value)...) + ValidateCookieArray(sch, p, cookie.Value, pathValue, operation, renderedSchema)...) } } @@ -143,7 +154,7 @@ func (v *paramValidator) ValidateCookieParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch)) + errors.IncorrectCookieParamEnum(p, strings.ToLower(cookie.Value), sch, pathValue, operation, renderedSchema)) } } } diff --git a/parameters/header_parameters.go b/parameters/header_parameters.go index a4c56a1d..e370bb2a 100644 --- a/parameters/header_parameters.go +++ b/parameters/header_parameters.go @@ -4,6 +4,7 @@ package parameters import ( + "encoding/json" "fmt" "net/http" "strconv" @@ -47,6 +48,7 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, var validationErrors []*errors.ValidationError seenHeaders := make(map[string]bool) + operation := strings.ToLower(request.Method) for _, p := range params { if p.In == helpers.Header { @@ -57,6 +59,15 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, if p.Schema != nil { sch = p.Schema.Schema() } + + // Render schema once for ReferenceSchema field in errors + var renderedSchema string + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + pType := sch.Type for _, ty := range pType { @@ -64,7 +75,7 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, case helpers.Integer: if _, err := strconv.ParseInt(param, 10, 64); err != nil { validationErrors = append(validationErrors, - errors.InvalidHeaderParamInteger(p, strings.ToLower(param), sch)) + errors.InvalidHeaderParamInteger(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) break } // check if the param is within the enum @@ -78,14 +89,14 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectCookieParamEnum(p, strings.ToLower(param), sch)) + errors.IncorrectHeaderParamEnum(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) } } case helpers.Number: if _, err := strconv.ParseFloat(param, 64); err != nil { validationErrors = append(validationErrors, - errors.InvalidHeaderParamNumber(p, strings.ToLower(param), sch)) + errors.InvalidHeaderParamNumber(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) break } // check if the param is within the enum @@ -99,14 +110,14 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectCookieParamEnum(p, strings.ToLower(param), sch)) + errors.IncorrectHeaderParamEnum(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) } } case helpers.Boolean: if _, err := strconv.ParseBool(param); err != nil { validationErrors = append(validationErrors, - errors.IncorrectHeaderParamBool(p, strings.ToLower(param), sch)) + errors.IncorrectHeaderParamBool(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) } case helpers.Object: @@ -124,7 +135,7 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, if len(encodedObj) == 0 { validationErrors = append(validationErrors, - errors.HeaderParameterCannotBeDecoded(p, strings.ToLower(param))) + errors.HeaderParameterCannotBeDecoded(p, strings.ToLower(param), pathValue, operation, renderedSchema)) break } @@ -145,7 +156,7 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, if !p.IsExploded() { // only unexploded arrays are supported for cookie params if sch.Items.IsA() { validationErrors = append(validationErrors, - ValidateHeaderArray(sch, p, param)...) + ValidateHeaderArray(sch, p, param, pathValue, operation, renderedSchema)...) } } @@ -163,7 +174,7 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectHeaderParamEnum(p, strings.ToLower(param), sch)) + errors.IncorrectHeaderParamEnum(p, strings.ToLower(param), sch, pathValue, operation, renderedSchema)) } } } @@ -177,7 +188,17 @@ func (v *paramValidator) ValidateHeaderParamsWithPathItem(request *http.Request, } } else { if p.Required != nil && *p.Required { - validationErrors = append(validationErrors, errors.HeaderParameterMissing(p)) + // Render schema for missing required parameter + var renderedSchema string + if p.Schema != nil { + sch := p.Schema.Schema() + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + } + validationErrors = append(validationErrors, errors.HeaderParameterMissing(p, pathValue, operation, renderedSchema)) } } } diff --git a/parameters/path_parameters.go b/parameters/path_parameters.go index 31f7e3ce..78d83393 100644 --- a/parameters/path_parameters.go +++ b/parameters/path_parameters.go @@ -4,6 +4,7 @@ package parameters import ( + "encoding/json" "fmt" "net/http" "net/url" @@ -129,7 +130,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p if decodedParamValue == "" { // Mandatory path parameter cannot be empty if p.Required != nil && *p.Required { - validationErrors = append(validationErrors, errors.PathParameterMissing(p)) + validationErrors = append(validationErrors, errors.PathParameterMissing(p, pathValue, request.URL.Path)) break } continue @@ -138,6 +139,14 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p // extract the schema from the parameter sch := p.Schema.Schema() + // Render schema once for ReferenceSchema field in errors + var renderedSchema string + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + // check enum (if present) enumCheck := func(decodedValue string) { matchFound := false @@ -149,7 +158,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectPathParamEnum(p, strings.ToLower(decodedValue), sch)) + errors.IncorrectPathParamEnum(p, strings.ToLower(decodedValue), sch, pathValue, renderedSchema)) } } @@ -180,7 +189,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p case helpers.Integer: // simple use case is already handled in find param. - rawParamValue, paramValueParsed, err := v.resolveInteger(sch, p, isLabel, isMatrix, decodedParamValue) + rawParamValue, paramValueParsed, err := v.resolveInteger(sch, p, isLabel, isMatrix, decodedParamValue, pathValue, renderedSchema) if err != nil { validationErrors = append(validationErrors, err...) break @@ -203,7 +212,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p case helpers.Number: // simple use case is already handled in find param. - rawParamValue, paramValueParsed, err := v.resolveNumber(sch, p, isLabel, isMatrix, decodedParamValue) + rawParamValue, paramValueParsed, err := v.resolveNumber(sch, p, isLabel, isMatrix, decodedParamValue, pathValue, renderedSchema) if err != nil { validationErrors = append(validationErrors, err...) break @@ -228,13 +237,13 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p if isLabel && p.Style == helpers.LabelStyle { if _, err := strconv.ParseBool(decodedParamValue[1:]); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamBool(p, decodedParamValue[1:], sch)) + errors.IncorrectPathParamBool(p, decodedParamValue[1:], sch, pathValue, renderedSchema)) } } if isSimple { if _, err := strconv.ParseBool(decodedParamValue); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamBool(p, decodedParamValue, sch)) + errors.IncorrectPathParamBool(p, decodedParamValue, sch, pathValue, renderedSchema)) } } if isMatrix && p.Style == helpers.MatrixStyle { @@ -242,7 +251,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p decodedForMatrix := strings.Replace(decodedParamValue[1:], fmt.Sprintf("%s=", p.Name), "", 1) if _, err := strconv.ParseBool(decodedForMatrix); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamBool(p, decodedForMatrix, sch)) + errors.IncorrectPathParamBool(p, decodedForMatrix, sch, pathValue, renderedSchema)) } } case helpers.Object: @@ -290,6 +299,15 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p // extract the items schema in order to validate the array items. if sch.Items != nil && sch.Items.IsA() { iSch := sch.Items.A.Schema() + + // Render items schema once for ReferenceSchema field in array errors + var renderedItemsSchema string + if iSch != nil { + rendered, _ := iSch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedItemsSchema = string(schemaBytes) + } + for n := range iSch.Type { // determine how to explode the array var arrayValues []string @@ -317,14 +335,14 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p for pv := range arrayValues { if _, err := strconv.ParseInt(arrayValues[pv], 10, 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamArrayInteger(p, arrayValues[pv], sch, iSch)) + errors.IncorrectPathParamArrayInteger(p, arrayValues[pv], sch, iSch, pathValue, renderedItemsSchema)) } } case helpers.Number: for pv := range arrayValues { if _, err := strconv.ParseFloat(arrayValues[pv], 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamArrayNumber(p, arrayValues[pv], sch, iSch)) + errors.IncorrectPathParamArrayNumber(p, arrayValues[pv], sch, iSch, pathValue, renderedItemsSchema)) } } case helpers.Boolean: @@ -332,7 +350,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p bc := len(validationErrors) if _, err := strconv.ParseBool(arrayValues[pv]); err != nil { validationErrors = append(validationErrors, - errors.IncorrectPathParamArrayBoolean(p, arrayValues[pv], sch, iSch)) + errors.IncorrectPathParamArrayBoolean(p, arrayValues[pv], sch, iSch, pathValue, renderedItemsSchema)) continue } if len(validationErrors) == bc { @@ -340,7 +358,7 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p // need to catch this edge case. if arrayValues[pv] == "0" || arrayValues[pv] == "1" { validationErrors = append(validationErrors, - errors.IncorrectPathParamArrayBoolean(p, arrayValues[pv], sch, iSch)) + errors.IncorrectPathParamArrayBoolean(p, arrayValues[pv], sch, iSch, pathValue, renderedItemsSchema)) continue } } @@ -364,11 +382,11 @@ func (v *paramValidator) ValidatePathParamsWithPathItem(request *http.Request, p return true, nil } -func (v *paramValidator) resolveNumber(sch *base.Schema, p *v3.Parameter, isLabel bool, isMatrix bool, paramValue string) (string, float64, []*errors.ValidationError) { +func (v *paramValidator) resolveNumber(sch *base.Schema, p *v3.Parameter, isLabel bool, isMatrix bool, paramValue string, pathValue string, renderedSchema string) (string, float64, []*errors.ValidationError) { if isLabel && p.Style == helpers.LabelStyle { paramValueParsed, err := strconv.ParseFloat(paramValue[1:], 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue[1:], sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue[1:], sch, pathValue, renderedSchema)} } return paramValue[1:], paramValueParsed, nil } @@ -377,22 +395,22 @@ func (v *paramValidator) resolveNumber(sch *base.Schema, p *v3.Parameter, isLabe paramValue = strings.Replace(paramValue[1:], fmt.Sprintf("%s=", p.Name), "", 1) paramValueParsed, err := strconv.ParseFloat(paramValue, 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue[1:], sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue[1:], sch, pathValue, renderedSchema)} } return paramValue, paramValueParsed, nil } paramValueParsed, err := strconv.ParseFloat(paramValue, 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue, sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamNumber(p, paramValue, sch, pathValue, renderedSchema)} } return paramValue, paramValueParsed, nil } -func (v *paramValidator) resolveInteger(sch *base.Schema, p *v3.Parameter, isLabel bool, isMatrix bool, paramValue string) (string, int64, []*errors.ValidationError) { +func (v *paramValidator) resolveInteger(sch *base.Schema, p *v3.Parameter, isLabel bool, isMatrix bool, paramValue string, pathValue string, renderedSchema string) (string, int64, []*errors.ValidationError) { if isLabel && p.Style == helpers.LabelStyle { paramValueParsed, err := strconv.ParseInt(paramValue[1:], 10, 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue[1:], sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue[1:], sch, pathValue, renderedSchema)} } return paramValue[1:], paramValueParsed, nil } @@ -401,13 +419,13 @@ func (v *paramValidator) resolveInteger(sch *base.Schema, p *v3.Parameter, isLab paramValue = strings.Replace(paramValue[1:], fmt.Sprintf("%s=", p.Name), "", 1) paramValueParsed, err := strconv.ParseInt(paramValue, 10, 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue[1:], sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue[1:], sch, pathValue, renderedSchema)} } return paramValue, paramValueParsed, nil } paramValueParsed, err := strconv.ParseInt(paramValue, 10, 64) if err != nil { - return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue, sch)} + return "", 0, []*errors.ValidationError{errors.IncorrectPathParamInteger(p, paramValue, sch, pathValue, renderedSchema)} } return paramValue, paramValueParsed, nil } diff --git a/parameters/query_parameters.go b/parameters/query_parameters.go index 888cbc8c..91fe90c3 100644 --- a/parameters/query_parameters.go +++ b/parameters/query_parameters.go @@ -70,6 +70,9 @@ func (v *paramValidator) ValidateQueryParamsWithPathItem(request *http.Request, } } + // Get operation from request method (lowercase for JSON Pointer) + operation := strings.ToLower(request.Method) + // look through the params for the query key doneLooking: for p := range params { @@ -101,6 +104,15 @@ doneLooking: break } } + + // Render schema once for ReferenceSchema field in errors + var renderedSchema string + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + pType := sch.Type // for each param, check each type @@ -113,34 +125,34 @@ doneLooking: if !params[p].AllowReserved { if rxRxp.MatchString(ef) && params[p].IsExploded() { validationErrors = append(validationErrors, - errors.IncorrectReservedValues(params[p], ef, sch)) + errors.IncorrectReservedValues(params[p], ef, sch, pathValue, operation, renderedSchema)) } } for _, ty := range pType { switch ty { case helpers.String: - validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, ef, params[p])...) + validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, ef, params[p], pathValue, operation, renderedSchema)...) case helpers.Integer: efF, err := strconv.ParseInt(ef, 10, 64) if err != nil { validationErrors = append(validationErrors, - errors.InvalidQueryParamInteger(params[p], ef, sch)) + errors.InvalidQueryParamInteger(params[p], ef, sch, pathValue, operation, renderedSchema)) break } - validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, efF, params[p])...) + validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, efF, params[p], pathValue, operation, renderedSchema)...) case helpers.Number: efF, err := strconv.ParseFloat(ef, 64) if err != nil { validationErrors = append(validationErrors, - errors.InvalidQueryParamNumber(params[p], ef, sch)) + errors.InvalidQueryParamNumber(params[p], ef, sch, pathValue, operation, renderedSchema)) break } - validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, efF, params[p])...) + validationErrors = append(validationErrors, v.validateSimpleParam(sch, ef, efF, params[p], pathValue, operation, renderedSchema)...) case helpers.Boolean: if _, err := strconv.ParseBool(ef); err != nil { validationErrors = append(validationErrors, - errors.IncorrectQueryParamBool(params[p], ef, sch)) + errors.IncorrectQueryParamBool(params[p], ef, sch, pathValue, operation, renderedSchema)) } case helpers.Object: @@ -165,7 +177,7 @@ doneLooking: encodedObj = make(map[string]interface{}) if err := json.Unmarshal([]byte(ef), &encodedParams); err != nil { validationErrors = append(validationErrors, - errors.IncorrectParamEncodingJSON(params[p], ef, sch)) + errors.IncorrectParamEncodingJSON(params[p], ef, sch, pathValue, operation, renderedSchema)) break skipValues } encodedObj[params[p].Name] = encodedParams @@ -195,7 +207,7 @@ doneLooking: // only check if items is a schema, not a boolean if sch.Items != nil && sch.Items.IsA() { validationErrors = append(validationErrors, - ValidateQueryArray(sch, params[p], ef, contentWrapped, v.options)...) + ValidateQueryArray(sch, params[p], ef, contentWrapped, v.options, pathValue, operation, renderedSchema)...) } } } @@ -225,7 +237,23 @@ doneLooking: } // if there is no match, check if the param is required or not. if params[p].Required != nil && *params[p].Required { - validationErrors = append(validationErrors, errors.QueryParameterMissing(params[p])) + // Render schema for missing parameter + var sch *base.Schema + if params[p].Schema != nil { + sch = params[p].Schema.Schema() + } else { + for pair := orderedmap.First(params[p].Content); pair != nil; pair = pair.Next() { + sch = pair.Value().Schema.Schema() + break + } + } + var renderedSchema string + if sch != nil { + rendered, _ := sch.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedSchema = string(schemaBytes) + } + validationErrors = append(validationErrors, errors.QueryParameterMissing(params[p], pathValue, operation, renderedSchema)) } } } @@ -239,7 +267,7 @@ doneLooking: return true, nil } -func (v *paramValidator) validateSimpleParam(sch *base.Schema, rawParam string, parsedParam any, parameter *v3.Parameter) (validationErrors []*errors.ValidationError) { +func (v *paramValidator) validateSimpleParam(sch *base.Schema, rawParam string, parsedParam any, parameter *v3.Parameter, pathTemplate string, operation string, renderedSchema string) (validationErrors []*errors.ValidationError) { // check if the param is within an enum if sch.Enum != nil { matchFound := false @@ -250,11 +278,11 @@ func (v *paramValidator) validateSimpleParam(sch *base.Schema, rawParam string, } } if !matchFound { - return []*errors.ValidationError{errors.IncorrectQueryParamEnum(parameter, rawParam, sch)} + return []*errors.ValidationError{errors.IncorrectQueryParamEnum(parameter, rawParam, sch, pathTemplate, operation, renderedSchema)} } } - return ValidateSingleParameterSchema( + return ValidateSingleParameterSchemaWithPath( sch, parsedParam, "Query parameter", @@ -263,5 +291,7 @@ func (v *paramValidator) validateSimpleParam(sch *base.Schema, rawParam string, helpers.ParameterValidation, helpers.ParameterValidationQuery, v.options, + pathTemplate, + operation, ) } diff --git a/parameters/validate_parameter.go b/parameters/validate_parameter.go index 2885369b..df5ae8b4 100644 --- a/parameters/validate_parameter.go +++ b/parameters/validate_parameter.go @@ -33,6 +33,21 @@ func ValidateSingleParameterSchema( validationType string, subValType string, o *config.ValidationOptions, +) (validationErrors []*errors.ValidationError) { + return ValidateSingleParameterSchemaWithPath(schema, rawObject, entity, reasonEntity, name, validationType, subValType, o, "", "") +} + +func ValidateSingleParameterSchemaWithPath( + schema *base.Schema, + rawObject any, + entity string, + reasonEntity string, + name string, + validationType string, + subValType string, + o *config.ValidationOptions, + pathTemplate string, + operation string, ) (validationErrors []*errors.ValidationError) { // Get the JSON Schema for the parameter definition. jsonSchema, err := buildJsonRender(schema) @@ -50,7 +65,7 @@ func ValidateSingleParameterSchema( scErrs := jsch.Validate(rawObject) var werras *jsonschema.ValidationError if stdError.As(scErrs, &werras) { - validationErrors = formatJsonSchemaValidationError(schema, werras, entity, reasonEntity, name, validationType, subValType) + validationErrors = formatJsonSchemaValidationError(schema, werras, entity, reasonEntity, name, validationType, subValType, pathTemplate, operation) } return validationErrors } @@ -183,7 +198,7 @@ func ValidateParameterSchema( } var werras *jsonschema.ValidationError if stdError.As(scErrs, &werras) { - validationErrors = formatJsonSchemaValidationError(schema, werras, entity, reasonEntity, name, validationType, subValType) + validationErrors = formatJsonSchemaValidationError(schema, werras, entity, reasonEntity, name, validationType, subValType, "", "") } // if there are no validationErrors, check that the supplied value is even JSON @@ -207,7 +222,7 @@ func ValidateParameterSchema( return validationErrors } -func formatJsonSchemaValidationError(schema *base.Schema, scErrs *jsonschema.ValidationError, entity string, reasonEntity string, name string, validationType string, subValType string) (validationErrors []*errors.ValidationError) { +func formatJsonSchemaValidationError(schema *base.Schema, scErrs *jsonschema.ValidationError, entity string, reasonEntity string, name string, validationType string, subValType string, pathTemplate string, operation string) (validationErrors []*errors.ValidationError) { // flatten the validationErrors schFlatErrs := scErrs.BasicOutput().Errors var schemaValidationErrors []*errors.SchemaValidationFailure @@ -219,19 +234,33 @@ func formatJsonSchemaValidationError(schema *base.Schema, scErrs *jsonschema.Val continue // ignore this error, it's not useful } + // Construct full OpenAPI path for KeywordLocation if pathTemplate and operation are provided + keywordLocation := er.KeywordLocation + if pathTemplate != "" && operation != "" && validationType == helpers.ParameterValidation { + // Build full OpenAPI path: /paths/{escapedPath}/{operation}/parameters/{paramName}/schema{relativeKeywordLocation} + escapedPath := strings.ReplaceAll(pathTemplate, "~", "~0") + escapedPath = strings.ReplaceAll(escapedPath, "/", "~1") + escapedPath = strings.TrimPrefix(escapedPath, "~1") // Remove leading ~1 + + // er.KeywordLocation is relative to the schema (e.g., "/minLength" or "/enum") + // Prepend the full OpenAPI path + keywordLocation = fmt.Sprintf("/paths/%s/%s/parameters/%s/schema%s", escapedPath, strings.ToLower(operation), name, er.KeywordLocation) + } + fail := &errors.SchemaValidationFailure{ Reason: errMsg, Location: er.KeywordLocation, // DEPRECATED FieldName: helpers.ExtractFieldNameFromStringLocation(er.InstanceLocation), FieldPath: helpers.ExtractJSONPathFromStringLocation(er.InstanceLocation), InstancePath: helpers.ConvertStringLocationToPathSegments(er.InstanceLocation), - KeywordLocation: er.KeywordLocation, + KeywordLocation: keywordLocation, OriginalJsonSchemaError: scErrs, } if schema != nil { rendered, err := schema.RenderInline() if err == nil && rendered != nil { - fail.ReferenceSchema = string(rendered) + renderedBytes, _ := json.Marshal(rendered) + fail.ReferenceSchema = string(renderedBytes) } } schemaValidationErrors = append(schemaValidationErrors, fail) diff --git a/parameters/validation_functions.go b/parameters/validation_functions.go index f1080a59..f931588f 100644 --- a/parameters/validation_functions.go +++ b/parameters/validation_functions.go @@ -4,13 +4,14 @@ package parameters import ( + "encoding/json" "fmt" "slices" "strconv" "strings" "github.com/pb33f/libopenapi/datamodel/high/base" - "github.com/pb33f/libopenapi/datamodel/high/v3" + v3 "github.com/pb33f/libopenapi/datamodel/high/v3" "github.com/pb33f/libopenapi-validator/config" "github.com/pb33f/libopenapi-validator/errors" @@ -19,11 +20,18 @@ import ( // ValidateCookieArray will validate a cookie parameter that is an array func ValidateCookieArray( - sch *base.Schema, param *v3.Parameter, value string, + sch *base.Schema, param *v3.Parameter, value string, pathTemplate string, operation string, renderedSchema string, ) []*errors.ValidationError { var validationErrors []*errors.ValidationError itemsSchema := sch.Items.A.Schema() + var renderedItemsSchema string + if itemsSchema != nil { + rendered, _ := itemsSchema.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedItemsSchema = string(schemaBytes) + } + // header arrays can only be encoded as CSV items := helpers.ExplodeQueryValue(value, helpers.DefaultDelimited) @@ -35,18 +43,18 @@ func ValidateCookieArray( case helpers.Integer, helpers.Number: if _, err := strconv.ParseFloat(item, 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectCookieParamArrayNumber(param, item, sch, itemsSchema)) + errors.IncorrectCookieParamArrayNumber(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) } case helpers.Boolean: if _, err := strconv.ParseBool(item); err != nil { validationErrors = append(validationErrors, - errors.IncorrectCookieParamArrayBoolean(param, item, sch, itemsSchema)) + errors.IncorrectCookieParamArrayBoolean(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) break } // check for edge-cases "0" and "1" which can also be parsed into valid booleans if item == "0" || item == "1" { validationErrors = append(validationErrors, - errors.IncorrectCookieParamArrayBoolean(param, item, sch, itemsSchema)) + errors.IncorrectCookieParamArrayBoolean(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) } case helpers.String: // do nothing for now. @@ -59,11 +67,18 @@ func ValidateCookieArray( // ValidateHeaderArray will validate a header parameter that is an array func ValidateHeaderArray( - sch *base.Schema, param *v3.Parameter, value string, + sch *base.Schema, param *v3.Parameter, value string, pathTemplate string, operation string, renderedSchema string, ) []*errors.ValidationError { var validationErrors []*errors.ValidationError itemsSchema := sch.Items.A.Schema() + var renderedItemsSchema string + if itemsSchema != nil { + rendered, _ := itemsSchema.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedItemsSchema = string(schemaBytes) + } + // header arrays can only be encoded as CSV items := helpers.ExplodeQueryValue(value, helpers.DefaultDelimited) @@ -75,18 +90,18 @@ func ValidateHeaderArray( case helpers.Integer, helpers.Number: if _, err := strconv.ParseFloat(item, 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectHeaderParamArrayNumber(param, item, sch, itemsSchema)) + errors.IncorrectHeaderParamArrayNumber(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) } case helpers.Boolean: if _, err := strconv.ParseBool(item); err != nil { validationErrors = append(validationErrors, - errors.IncorrectHeaderParamArrayBoolean(param, item, sch, itemsSchema)) + errors.IncorrectHeaderParamArrayBoolean(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) break } // check for edge-cases "0" and "1" which can also be parsed into valid booleans if item == "0" || item == "1" { validationErrors = append(validationErrors, - errors.IncorrectHeaderParamArrayBoolean(param, item, sch, itemsSchema)) + errors.IncorrectHeaderParamArrayBoolean(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) } case helpers.String: // do nothing for now. @@ -99,11 +114,18 @@ func ValidateHeaderArray( // ValidateQueryArray will validate a query parameter that is an array func ValidateQueryArray( - sch *base.Schema, param *v3.Parameter, ef string, contentWrapped bool, validationOptions *config.ValidationOptions, + sch *base.Schema, param *v3.Parameter, ef string, contentWrapped bool, validationOptions *config.ValidationOptions, pathTemplate string, operation string, renderedSchema string, ) []*errors.ValidationError { var validationErrors []*errors.ValidationError itemsSchema := sch.Items.A.Schema() + var renderedItemsSchema string + if itemsSchema != nil { + rendered, _ := itemsSchema.RenderInline() + schemaBytes, _ := json.Marshal(rendered) + renderedItemsSchema = string(schemaBytes) + } + // check for an exploded bit on the schema. // if it's exploded, then we need to check each item in the array // if it's not exploded, then we need to check the whole array as a string @@ -141,7 +163,7 @@ func ValidateQueryArray( } if !matchFound { validationErrors = append(validationErrors, - errors.IncorrectQueryParamEnumArray(param, item, sch)) + errors.IncorrectQueryParamEnumArray(param, item, sch, pathTemplate, operation, renderedItemsSchema)) } } } @@ -165,7 +187,7 @@ func ValidateQueryArray( case helpers.Integer: if _, err := strconv.ParseInt(item, 10, 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectQueryParamArrayInteger(param, item, sch, itemsSchema)) + errors.IncorrectQueryParamArrayInteger(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) break } // will it blend? @@ -173,7 +195,7 @@ func ValidateQueryArray( case helpers.Number: if _, err := strconv.ParseFloat(item, 64); err != nil { validationErrors = append(validationErrors, - errors.IncorrectQueryParamArrayNumber(param, item, sch, itemsSchema)) + errors.IncorrectQueryParamArrayNumber(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) break } // will it blend? @@ -182,7 +204,7 @@ func ValidateQueryArray( case helpers.Boolean: if _, err := strconv.ParseBool(item); err != nil { validationErrors = append(validationErrors, - errors.IncorrectQueryParamArrayBoolean(param, item, sch, itemsSchema)) + errors.IncorrectQueryParamArrayBoolean(param, item, sch, itemsSchema, pathTemplate, operation, renderedItemsSchema)) } case helpers.Object: validationErrors = append(validationErrors, @@ -207,14 +229,14 @@ func ValidateQueryArray( if sch.MaxItems != nil { if len(items) > int(*sch.MaxItems) { validationErrors = append(validationErrors, - errors.IncorrectParamArrayMaxNumItems(param, sch, *sch.MaxItems, int64(len(items)))) + errors.IncorrectParamArrayMaxNumItems(param, sch, *sch.MaxItems, int64(len(items)), pathTemplate, operation, renderedSchema)) } } if sch.MinItems != nil { if len(items) < int(*sch.MinItems) { validationErrors = append(validationErrors, - errors.IncorrectParamArrayMinNumItems(param, sch, *sch.MinItems, int64(len(items)))) + errors.IncorrectParamArrayMinNumItems(param, sch, *sch.MinItems, int64(len(items)), pathTemplate, operation, renderedSchema)) } } @@ -222,7 +244,7 @@ func ValidateQueryArray( if sch.UniqueItems != nil { if *sch.UniqueItems && !uniqueItems { validationErrors = append(validationErrors, - errors.IncorrectParamArrayUniqueItems(param, sch, strings.Join(duplicates, ", "))) + errors.IncorrectParamArrayUniqueItems(param, sch, strings.Join(duplicates, ", "), pathTemplate, operation, renderedSchema)) } } return validationErrors