Skip to content

Commit 90ec52a

Browse files
committed
Cleaned up a bunch of stuff
Consuming the validator as part of a mocking engine turned up a few usability issues. Also cleaned up formatting Signed-off-by: Dave Shanley <[email protected]>
1 parent ceae216 commit 90ec52a

21 files changed

+2733
-2490
lines changed

errors/parameter_errors.go

Lines changed: 376 additions & 376 deletions
Large diffs are not rendered by default.

errors/request_errors.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,29 @@
44
package errors
55

66
import (
7-
"fmt"
8-
"github.com/pb33f/libopenapi-validator/helpers"
9-
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
10-
"net/http"
11-
"strings"
7+
"fmt"
8+
"github.com/pb33f/libopenapi-validator/helpers"
9+
v3 "github.com/pb33f/libopenapi/datamodel/high/v3"
10+
"net/http"
11+
"strings"
1212
)
1313

1414
func RequestContentTypeNotFound(op *v3.Operation, request *http.Request) *ValidationError {
15-
ct := request.Header.Get(helpers.ContentTypeHeader)
16-
var ctypes []string
17-
for k := range op.RequestBody.Content {
18-
ctypes = append(ctypes, k)
19-
}
20-
return &ValidationError{
21-
ValidationType: helpers.RequestBodyValidation,
22-
ValidationSubType: helpers.RequestBodyContentType,
23-
Message: fmt.Sprintf("%s operation request content type '%s' does not exist",
24-
request.Method, ct),
25-
Reason: fmt.Sprintf("The content type '%s' of the %s request submitted has not "+
26-
"been defined, it's an unknown type", ct, request.Method),
27-
SpecLine: op.RequestBody.GoLow().Content.KeyNode.Line,
28-
SpecCol: op.RequestBody.GoLow().Content.KeyNode.Column,
29-
Context: op,
30-
HowToFix: fmt.Sprintf(HowToFixInvalidContentType, len(op.RequestBody.Content), strings.Join(ctypes, ", ")),
31-
}
15+
ct := request.Header.Get(helpers.ContentTypeHeader)
16+
var ctypes []string
17+
for k := range op.RequestBody.Content {
18+
ctypes = append(ctypes, k)
19+
}
20+
return &ValidationError{
21+
ValidationType: helpers.RequestBodyValidation,
22+
ValidationSubType: helpers.RequestBodyContentType,
23+
Message: fmt.Sprintf("%s operation request content type '%s' does not exist",
24+
request.Method, ct),
25+
Reason: fmt.Sprintf("The content type '%s' of the %s request submitted has not "+
26+
"been defined, it's an unknown type", ct, request.Method),
27+
SpecLine: op.RequestBody.GoLow().Content.KeyNode.Line,
28+
SpecCol: op.RequestBody.GoLow().Content.KeyNode.Column,
29+
Context: op,
30+
HowToFix: fmt.Sprintf(HowToFixInvalidContentType, len(op.RequestBody.Content), strings.Join(ctypes, ", ")),
31+
}
3232
}

errors/validation_error.go

Lines changed: 63 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,95 +4,105 @@
44
package errors
55

66
import (
7-
"fmt"
8-
"github.com/santhosh-tekuri/jsonschema/v5"
7+
"fmt"
8+
"github.com/santhosh-tekuri/jsonschema/v5"
99
)
1010

1111
// SchemaValidationFailure is a wrapper around the jsonschema.ValidationError object, to provide a more
1212
// user-friendly way to break down what went wrong.
1313
type SchemaValidationFailure struct {
14-
// Reason is a human-readable message describing the reason for the error.
15-
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
14+
// Reason is a human-readable message describing the reason for the error.
15+
Reason string `json:"reason,omitempty" yaml:"reason,omitempty"`
1616

17-
// Location is the XPath-like location of the validation failure
18-
Location string `json:"location,omitempty" yaml:"location,omitempty"`
17+
// Location is the XPath-like location of the validation failure
18+
Location string `json:"location,omitempty" yaml:"location,omitempty"`
1919

20-
// DeepLocation is the path to the validation failure as exposed by the jsonschema library.
21-
DeepLocation string `json:"deepLocation,omitempty" yaml:"deepLocation,omitempty"`
20+
// DeepLocation is the path to the validation failure as exposed by the jsonschema library.
21+
DeepLocation string `json:"deepLocation,omitempty" yaml:"deepLocation,omitempty"`
2222

23-
// AbsoluteLocation is the absolute path to the validation failure as exposed by the jsonschema library.
24-
AbsoluteLocation string `json:"absoluteLocation,omitempty" yaml:"absoluteLocation,omitempty"`
23+
// AbsoluteLocation is the absolute path to the validation failure as exposed by the jsonschema library.
24+
AbsoluteLocation string `json:"absoluteLocation,omitempty" yaml:"absoluteLocation,omitempty"`
2525

26-
// Line is the line number where the violation occurred. This may a local line number
27-
// if the validation is a schema (only schemas are validated locally, so the line number will be relative to
28-
// the Context object held by the ValidationError object).
29-
Line int `json:"line,omitempty" yaml:"line,omitempty"`
26+
// Line is the line number where the violation occurred. This may a local line number
27+
// if the validation is a schema (only schemas are validated locally, so the line number will be relative to
28+
// the Context object held by the ValidationError object).
29+
Line int `json:"line,omitempty" yaml:"line,omitempty"`
3030

31-
// Column is the column number where the violation occurred. This may a local column number
32-
// if the validation is a schema (only schemas are validated locally, so the column number will be relative to
33-
// the Context object held by the ValidationError object).
34-
Column int `json:"column,omitempty" yaml:"column,omitempty"`
31+
// Column is the column number where the violation occurred. This may a local column number
32+
// if the validation is a schema (only schemas are validated locally, so the column number will be relative to
33+
// the Context object held by the ValidationError object).
34+
Column int `json:"column,omitempty" yaml:"column,omitempty"`
3535

36-
// ReferenceSchema is the schema that was referenced in the validation failure.
37-
ReferenceSchema string `json:"referenceSchema,omitempty" yaml:"referenceSchema,omitempty"`
36+
// ReferenceSchema is the schema that was referenced in the validation failure.
37+
ReferenceSchema string `json:"referenceSchema,omitempty" yaml:"referenceSchema,omitempty"`
3838

39-
// ReferenceObject is the object that was referenced in the validation failure.
40-
ReferenceObject string `json:"referenceObject,omitempty" yaml:"referenceObject,omitempty"`
39+
// ReferenceObject is the object that was referenced in the validation failure.
40+
ReferenceObject string `json:"referenceObject,omitempty" yaml:"referenceObject,omitempty"`
4141

42-
// The original error object, which is a jsonschema.ValidationError object.
43-
OriginalError *jsonschema.ValidationError `json:"-" yaml:"-"`
42+
// The original error object, which is a jsonschema.ValidationError object.
43+
OriginalError *jsonschema.ValidationError `json:"-" yaml:"-"`
4444
}
4545

4646
// Error returns a string representation of the error
4747
func (s *SchemaValidationFailure) Error() string {
48-
return fmt.Sprintf("Reason: %s, Location: %s", s.Reason, s.Location)
48+
return fmt.Sprintf("Reason: %s, Location: %s", s.Reason, s.Location)
4949
}
5050

5151
// ValidationError is a struct that contains all the information about a validation error.
5252
type ValidationError struct {
5353

54-
// Message is a human-readable message describing the error.
55-
Message string `json:"message" yaml:"message"`
54+
// Message is a human-readable message describing the error.
55+
Message string `json:"message" yaml:"message"`
5656

57-
// Reason is a human-readable message describing the reason for the error.
58-
Reason string `json:"reason" yaml:"reason"`
57+
// Reason is a human-readable message describing the reason for the error.
58+
Reason string `json:"reason" yaml:"reason"`
5959

60-
// ValidationType is a string that describes the type of validation that failed.
61-
ValidationType string `json:"validationType" yaml:"validationType"`
60+
// ValidationType is a string that describes the type of validation that failed.
61+
ValidationType string `json:"validationType" yaml:"validationType"`
6262

63-
// ValidationSubType is a string that describes the subtype of validation that failed.
64-
ValidationSubType string `json:"validationSubType" yaml:"validationSubType"`
63+
// ValidationSubType is a string that describes the subtype of validation that failed.
64+
ValidationSubType string `json:"validationSubType" yaml:"validationSubType"`
6565

66-
// SpecLine is the line number in the spec where the error occurred.
67-
SpecLine int `json:"specLine" yaml:"specLine"`
66+
// SpecLine is the line number in the spec where the error occurred.
67+
SpecLine int `json:"specLine" yaml:"specLine"`
6868

69-
// SpecCol is the column number in the spec where the error occurred.
70-
SpecCol int `json:"specColumn" yaml:"specColumn"`
69+
// SpecCol is the column number in the spec where the error occurred.
70+
SpecCol int `json:"specColumn" yaml:"specColumn"`
7171

72-
// HowToFix is a human-readable message describing how to fix the error.
73-
HowToFix string `json:"howToFix" yaml:"howToFix"`
72+
// HowToFix is a human-readable message describing how to fix the error.
73+
HowToFix string `json:"howToFix" yaml:"howToFix"`
7474

75-
// SchemaValidationErrors is a slice of SchemaValidationFailure objects that describe the validation errors
76-
// This is only populated whe the validation type is against a schema.
77-
SchemaValidationErrors []*SchemaValidationFailure `json:"validationErrors,omitempty" yaml:"validationErrors,omitempty"`
75+
// SchemaValidationErrors is a slice of SchemaValidationFailure objects that describe the validation errors
76+
// This is only populated whe the validation type is against a schema.
77+
SchemaValidationErrors []*SchemaValidationFailure `json:"validationErrors,omitempty" yaml:"validationErrors,omitempty"`
7878

79-
// Context is the object that the validation error occurred on. This is usually a pointer to a schema
80-
// or a parameter object.
81-
Context interface{} `json:"-" yaml:"-"`
79+
// Context is the object that the validation error occurred on. This is usually a pointer to a schema
80+
// or a parameter object.
81+
Context interface{} `json:"-" yaml:"-"`
8282
}
8383

8484
// Error returns a string representation of the error
8585
func (v *ValidationError) Error() string {
86-
if v.SchemaValidationErrors != nil {
87-
return fmt.Sprintf("Error: %s, Reason: %s, Validation Errors: %s, Line: %d, Column: %d",
88-
v.Message, v.Reason, v.SchemaValidationErrors, v.SpecLine, v.SpecCol)
89-
} else {
90-
return fmt.Sprintf("Error: %s, Reason: %s, Line: %d, Column: %d",
91-
v.Message, v.Reason, v.SpecLine, v.SpecCol)
92-
}
86+
if v.SchemaValidationErrors != nil {
87+
if v.SpecLine > 0 && v.SpecCol > 0 {
88+
return fmt.Sprintf("Error: %s, Reason: %s, Validation Errors: %s, Line: %d, Column: %d",
89+
v.Message, v.Reason, v.SchemaValidationErrors, v.SpecLine, v.SpecCol)
90+
} else {
91+
return fmt.Sprintf("Error: %s, Reason: %s, Validation Errors: %s",
92+
v.Message, v.Reason, v.SchemaValidationErrors)
93+
}
94+
} else {
95+
if v.SpecLine > 0 && v.SpecCol > 0 {
96+
return fmt.Sprintf("Error: %s, Reason: %s, Line: %d, Column: %d",
97+
v.Message, v.Reason, v.SpecLine, v.SpecCol)
98+
} else {
99+
return fmt.Sprintf("Error: %s, Reason: %s",
100+
v.Message, v.Reason)
101+
}
102+
}
93103
}
94104

95105
// IsPathMissingError returns true if the error has a ValidationType of "path" and a ValidationSubType of "missing"
96106
func (v *ValidationError) IsPathMissingError() bool {
97-
return v.ValidationType == "path" && v.ValidationSubType == "missing"
107+
return v.ValidationType == "path" && v.ValidationSubType == "missing"
98108
}

helpers/constants.go

Lines changed: 42 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,46 @@
44
package helpers
55

66
const (
7-
ParameterValidation = "parameter"
8-
ParameterValidationPath = "path"
9-
ParameterValidationQuery = "query"
10-
ParameterValidationHeader = "header"
11-
ParameterValidationCookie = "cookie"
12-
RequestBodyValidation = "requestBody"
13-
Schema = "schema"
14-
ResponseBodyValidation = "response"
15-
RequestBodyContentType = "contentType"
16-
ResponseBodyResponseCode = "statusCode"
17-
SpaceDelimited = "spaceDelimited"
18-
PipeDelimited = "pipeDelimited"
19-
DefaultDelimited = "default"
20-
MatrixStyle = "matrix"
21-
LabelStyle = "label"
22-
Pipe = "|"
23-
Comma = ","
24-
Space = " "
25-
SemiColon = ";"
26-
Asterisk = "*"
27-
Period = "."
28-
Equals = "="
29-
Integer = "integer"
30-
Number = "number"
31-
Slash = "/"
32-
Object = "object"
33-
String = "string"
34-
Array = "array"
35-
Boolean = "boolean"
36-
DeepObject = "deepObject"
37-
Header = "header"
38-
Cookie = "cookie"
39-
Path = "path"
40-
Form = "form"
41-
Query = "query"
42-
JSONContentType = "application/json"
43-
JSONType = "json"
44-
ContentTypeHeader = "Content-Type"
45-
Charset = "charset"
46-
Boundary = "boundary"
47-
FailSegment = "**&&FAIL&&**"
7+
ParameterValidation = "parameter"
8+
ParameterValidationPath = "path"
9+
ParameterValidationQuery = "query"
10+
ParameterValidationHeader = "header"
11+
ParameterValidationCookie = "cookie"
12+
RequestBodyValidation = "requestBody"
13+
Schema = "schema"
14+
ResponseBodyValidation = "response"
15+
RequestBodyContentType = "contentType"
16+
ResponseBodyResponseCode = "statusCode"
17+
SpaceDelimited = "spaceDelimited"
18+
PipeDelimited = "pipeDelimited"
19+
DefaultDelimited = "default"
20+
MatrixStyle = "matrix"
21+
LabelStyle = "label"
22+
Pipe = "|"
23+
Comma = ","
24+
Space = " "
25+
SemiColon = ";"
26+
Asterisk = "*"
27+
Period = "."
28+
Equals = "="
29+
Integer = "integer"
30+
Number = "number"
31+
Slash = "/"
32+
Object = "object"
33+
String = "string"
34+
Array = "array"
35+
Boolean = "boolean"
36+
DeepObject = "deepObject"
37+
Header = "header"
38+
Cookie = "cookie"
39+
Path = "path"
40+
Form = "form"
41+
Query = "query"
42+
JSONContentType = "application/json"
43+
JSONType = "json"
44+
ContentTypeHeader = "Content-Type"
45+
Charset = "charset"
46+
Boundary = "boundary"
47+
Preferred = "preferred"
48+
FailSegment = "**&&FAIL&&**"
4849
)

helpers/operation_utilities.go

Lines changed: 41 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,56 +4,56 @@
44
package helpers
55

66
import (
7-
"github.com/pb33f/libopenapi/datamodel/high/v3"
8-
"net/http"
9-
"strings"
7+
"github.com/pb33f/libopenapi/datamodel/high/v3"
8+
"net/http"
9+
"strings"
1010
)
1111

1212
// ExtractOperation extracts the operation from the path item based on the request method. If there is no
1313
// matching operation found, then nil is returned.
1414
func ExtractOperation(request *http.Request, item *v3.PathItem) *v3.Operation {
15-
switch request.Method {
16-
case http.MethodGet:
17-
return item.Get
18-
case http.MethodPost:
19-
return item.Post
20-
case http.MethodPut:
21-
return item.Put
22-
case http.MethodDelete:
23-
return item.Delete
24-
case http.MethodOptions:
25-
return item.Options
26-
case http.MethodHead:
27-
return item.Head
28-
case http.MethodPatch:
29-
return item.Patch
30-
case http.MethodTrace:
31-
return item.Trace
32-
}
33-
return nil
15+
switch request.Method {
16+
case http.MethodGet:
17+
return item.Get
18+
case http.MethodPost:
19+
return item.Post
20+
case http.MethodPut:
21+
return item.Put
22+
case http.MethodDelete:
23+
return item.Delete
24+
case http.MethodOptions:
25+
return item.Options
26+
case http.MethodHead:
27+
return item.Head
28+
case http.MethodPatch:
29+
return item.Patch
30+
case http.MethodTrace:
31+
return item.Trace
32+
}
33+
return nil
3434
}
3535

3636
// ExtractContentType extracts the content type from the request header. First return argument is the content type
3737
// of the request.The second (optional) argument is the charset of the request. The third (optional)
3838
// argument is the boundary of the type (only used with forms really).
3939
func ExtractContentType(contentType string) (string, string, string) {
40-
var charset, boundary string
41-
if strings.ContainsRune(contentType, ';') {
42-
segs := strings.Split(contentType, SemiColon)
43-
contentType = strings.TrimSpace(segs[0])
44-
for _, v := range segs[1:] {
45-
kv := strings.Split(v, Equals)
46-
if len(kv) == 2 {
47-
if strings.TrimSpace(strings.ToLower(kv[0])) == Charset {
48-
charset = strings.TrimSpace(kv[1])
49-
}
50-
if strings.TrimSpace(strings.ToLower(kv[0])) == Boundary {
51-
boundary = strings.TrimSpace(kv[1])
52-
}
53-
}
54-
}
55-
} else {
56-
contentType = strings.TrimSpace(contentType)
57-
}
58-
return contentType, charset, boundary
40+
var charset, boundary string
41+
if strings.ContainsRune(contentType, ';') {
42+
segs := strings.Split(contentType, SemiColon)
43+
contentType = strings.TrimSpace(segs[0])
44+
for _, v := range segs[1:] {
45+
kv := strings.Split(v, Equals)
46+
if len(kv) == 2 {
47+
if strings.TrimSpace(strings.ToLower(kv[0])) == Charset {
48+
charset = strings.TrimSpace(kv[1])
49+
}
50+
if strings.TrimSpace(strings.ToLower(kv[0])) == Boundary {
51+
boundary = strings.TrimSpace(kv[1])
52+
}
53+
}
54+
}
55+
} else {
56+
contentType = strings.TrimSpace(contentType)
57+
}
58+
return contentType, charset, boundary
5959
}

0 commit comments

Comments
 (0)