Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add variadic options to Validate method #692

Merged
merged 3 commits into from Dec 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions .github/workflows/go.yml
Expand Up @@ -36,13 +36,13 @@ jobs:
- run: echo ${{ steps.go-cache-paths.outputs.go-mod }}

- name: Go Build Cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ${{ steps.go-cache-paths.outputs.go-build }}
key: ${{ runner.os }}-go-${{ matrix.go }}-build-${{ hashFiles('**/go.sum') }}

- name: Go Mod Cache (go>=1.15)
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ${{ steps.go-cache-paths.outputs.go-mod }}
key: ${{ runner.os }}-go-${{ matrix.go }}-mod-${{ hashFiles('**/go.sum') }}
Expand All @@ -61,6 +61,7 @@ jobs:
- run: go fmt ./...
- run: git --no-pager diff --exit-code

- run: go test ./...
- if: runner.os == 'Linux'
run: go test -count=10 ./...
env:
Expand Down Expand Up @@ -116,7 +117,7 @@ jobs:
fi

# Ensure impl Validate()
if ! git grep -InE 'func [(].+Schema[)] Validate[(]ctx context.Context[)].+error.+[{]'; then
if ! git grep -InE 'func [(].+'"$ty"'[)] Validate[(]ctx context.Context, opts [.][.][.]ValidationOption[)].+error.+[{]'; then
echo "OAI type $ty does not implement Validate()" && exit 1
fi

Expand Down
4 changes: 4 additions & 0 deletions README.md
Expand Up @@ -196,6 +196,10 @@ func arrayUniqueItemsChecker(items []interface{}) bool {

## Sub-v0 breaking API changes

### v0.111.0
* Changed `func (*_) Validate(ctx context.Context) error` to `func (*_) Validate(ctx context.Context, opts ...ValidationOption) error`.
* `openapi3.WithValidationOptions(ctx context.Context, opts *ValidationOptions) context.Context` prototype changed to `openapi3.WithValidationOptions(ctx context.Context, opts ...ValidationOption) context.Context`.

### v0.101.0
* `openapi3.SchemaFormatValidationDisabled` has been removed in favour of an option `openapi3.EnableSchemaFormatValidation()` passed to `openapi3.T.Validate`. The default behaviour is also now to not validate formats, as the OpenAPI spec mentions the `format` is an open value.

Expand Down
4 changes: 3 additions & 1 deletion openapi3/callback.go
Expand Up @@ -30,7 +30,9 @@ func (c Callbacks) JSONLookup(token string) (interface{}, error) {
type Callback map[string]*PathItem

// Validate returns an error if Callback does not comply with the OpenAPI spec.
func (callback Callback) Validate(ctx context.Context) error {
func (callback Callback) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

keys := make([]string, 0, len(callback))
for key := range callback {
keys = append(keys, key)
Expand Down
4 changes: 3 additions & 1 deletion openapi3/components.go
Expand Up @@ -40,7 +40,9 @@ func (components *Components) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Components does not comply with the OpenAPI spec.
func (components *Components) Validate(ctx context.Context) (err error) {
func (components *Components) Validate(ctx context.Context, opts ...ValidationOption) (err error) {
ctx = WithValidationOptions(ctx, opts...)

schemas := make([]string, 0, len(components.Schemas))
for name := range components.Schemas {
schemas = append(schemas, name)
Expand Down
4 changes: 3 additions & 1 deletion openapi3/content.go
Expand Up @@ -106,7 +106,9 @@ func (content Content) Get(mime string) *MediaType {
}

// Validate returns an error if Content does not comply with the OpenAPI spec.
func (content Content) Validate(ctx context.Context) error {
func (content Content) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

keys := make([]string, 0, len(content))
for key := range content {
keys = append(keys, key)
Expand Down
4 changes: 3 additions & 1 deletion openapi3/discriminator.go
Expand Up @@ -26,6 +26,8 @@ func (discriminator *Discriminator) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Discriminator does not comply with the OpenAPI spec.
func (discriminator *Discriminator) Validate(ctx context.Context) error {
func (discriminator *Discriminator) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

return nil
}
4 changes: 3 additions & 1 deletion openapi3/encoding.go
Expand Up @@ -66,7 +66,9 @@ func (encoding *Encoding) SerializationMethod() *SerializationMethod {
}

// Validate returns an error if Encoding does not comply with the OpenAPI spec.
func (encoding *Encoding) Validate(ctx context.Context) error {
func (encoding *Encoding) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if encoding == nil {
return nil
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/example.go
Expand Up @@ -55,7 +55,9 @@ func (example *Example) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Example does not comply with the OpenAPI spec.
func (example *Example) Validate(ctx context.Context) error {
func (example *Example) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

if example.Value != nil && example.ExternalValue != "" {
return errors.New("value and externalValue are mutually exclusive")
}
Expand Down
8 changes: 3 additions & 5 deletions openapi3/example_validation_test.go
Expand Up @@ -221,8 +221,6 @@ func TestExamplesSchemaValidation(t *testing.T) {
t.Parallel()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
loader := NewLoader()

spec := bytes.Buffer{}
spec.WriteString(`
openapi: 3.0.3
Expand Down Expand Up @@ -339,13 +337,14 @@ components:
`)
spec.WriteString(tc.componentExamples)

loader := NewLoader()
doc, err := loader.LoadFromData(spec.Bytes())
require.NoError(t, err)

if testOption.disableExamplesValidation {
err = doc.Validate(loader.Context, DisableExamplesValidation())
} else {
err = doc.Validate(loader.Context)
err = doc.Validate(loader.Context, EnableExamplesValidation())
}

if tc.errContains != "" && !testOption.disableExamplesValidation {
Expand Down Expand Up @@ -436,8 +435,6 @@ func TestExampleObjectValidation(t *testing.T) {
t.Parallel()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
loader := NewLoader()

spec := bytes.Buffer{}
spec.WriteString(`
openapi: 3.0.3
Expand Down Expand Up @@ -506,6 +503,7 @@ components:
`)
spec.WriteString(tc.componentExamples)

loader := NewLoader()
doc, err := loader.LoadFromData(spec.Bytes())
require.NoError(t, err)

Expand Down
4 changes: 3 additions & 1 deletion openapi3/external_docs.go
Expand Up @@ -29,7 +29,9 @@ func (e *ExternalDocs) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if ExternalDocs does not comply with the OpenAPI spec.
func (e *ExternalDocs) Validate(ctx context.Context) error {
func (e *ExternalDocs) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

if e.URL == "" {
return errors.New("url is required")
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/header.go
Expand Up @@ -54,7 +54,9 @@ func (header *Header) SerializationMethod() (*SerializationMethod, error) {
}

// Validate returns an error if Header does not comply with the OpenAPI spec.
func (header *Header) Validate(ctx context.Context) error {
func (header *Header) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if header.Name != "" {
return errors.New("header 'name' MUST NOT be specified, it is given in the corresponding headers map")
}
Expand Down
12 changes: 9 additions & 3 deletions openapi3/info.go
Expand Up @@ -31,7 +31,9 @@ func (info *Info) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Info does not comply with the OpenAPI spec.
func (info *Info) Validate(ctx context.Context) error {
func (info *Info) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if contact := info.Contact; contact != nil {
if err := contact.Validate(ctx); err != nil {
return err
Expand Down Expand Up @@ -76,7 +78,9 @@ func (contact *Contact) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Contact does not comply with the OpenAPI spec.
func (contact *Contact) Validate(ctx context.Context) error {
func (contact *Contact) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

return nil
}

Expand All @@ -100,7 +104,9 @@ func (license *License) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if License does not comply with the OpenAPI spec.
func (license *License) Validate(ctx context.Context) error {
func (license *License) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

if license.Name == "" {
return errors.New("value of license name must be a non-empty string")
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/link.go
Expand Up @@ -51,7 +51,9 @@ func (link *Link) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if Link does not comply with the OpenAPI spec.
func (link *Link) Validate(ctx context.Context) error {
func (link *Link) Validate(ctx context.Context, opts ...ValidationOption) error {
// ctx = WithValidationOptions(ctx, opts...)

if link.OperationID == "" && link.OperationRef == "" {
return errors.New("missing operationId or operationRef on link")
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/media_type.go
Expand Up @@ -75,7 +75,9 @@ func (mediaType *MediaType) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if MediaType does not comply with the OpenAPI spec.
func (mediaType *MediaType) Validate(ctx context.Context) error {
func (mediaType *MediaType) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if mediaType == nil {
return nil
}
Expand Down
6 changes: 1 addition & 5 deletions openapi3/openapi3.go
Expand Up @@ -56,11 +56,7 @@ func (doc *T) AddServer(server *Server) {
// Validate returns an error if T does not comply with the OpenAPI spec.
// Validations Options can be provided to modify the validation behavior.
func (doc *T) Validate(ctx context.Context, opts ...ValidationOption) error {
validationOpts := &ValidationOptions{}
for _, opt := range opts {
opt(validationOpts)
}
ctx = WithValidationOptions(ctx, validationOpts)
ctx = WithValidationOptions(ctx, opts...)

if doc.OpenAPI == "" {
return errors.New("value of openapi must be a non-empty string")
Expand Down
4 changes: 3 additions & 1 deletion openapi3/operation.go
Expand Up @@ -127,7 +127,9 @@ func (operation *Operation) AddResponse(status int, response *Response) {
}

// Validate returns an error if Operation does not comply with the OpenAPI spec.
func (operation *Operation) Validate(ctx context.Context) error {
func (operation *Operation) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if v := operation.Parameters; v != nil {
if err := v.Validate(ctx); err != nil {
return err
Expand Down
8 changes: 6 additions & 2 deletions openapi3/parameter.go
Expand Up @@ -69,7 +69,9 @@ func (parameters Parameters) GetByInAndName(in string, name string) *Parameter {
}

// Validate returns an error if Parameters does not comply with the OpenAPI spec.
func (parameters Parameters) Validate(ctx context.Context) error {
func (parameters Parameters) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

dupes := make(map[string]struct{})
for _, parameterRef := range parameters {
if v := parameterRef.Value; v != nil {
Expand Down Expand Up @@ -247,7 +249,9 @@ func (parameter *Parameter) SerializationMethod() (*SerializationMethod, error)
}

// Validate returns an error if Parameter does not comply with the OpenAPI spec.
func (parameter *Parameter) Validate(ctx context.Context) error {
func (parameter *Parameter) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if parameter.Name == "" {
return errors.New("parameter name can't be blank")
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/path_item.go
Expand Up @@ -123,7 +123,9 @@ func (pathItem *PathItem) SetOperation(method string, operation *Operation) {
}

// Validate returns an error if PathItem does not comply with the OpenAPI spec.
func (pathItem *PathItem) Validate(ctx context.Context) error {
func (pathItem *PathItem) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

operations := pathItem.Operations()

methods := make([]string, 0, len(operations))
Expand Down
4 changes: 3 additions & 1 deletion openapi3/paths.go
Expand Up @@ -12,7 +12,9 @@ import (
type Paths map[string]*PathItem

// Validate returns an error if Paths does not comply with the OpenAPI spec.
func (paths Paths) Validate(ctx context.Context) error {
func (paths Paths) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

normalizedPaths := make(map[string]string, len(paths))

keys := make([]string, 0, len(paths))
Expand Down
27 changes: 18 additions & 9 deletions openapi3/refs.go
Expand Up @@ -39,7 +39,8 @@ func (value *CallbackRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if CallbackRef does not comply with the OpenAPI spec.
func (value *CallbackRef) Validate(ctx context.Context) error {
func (value *CallbackRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -81,7 +82,8 @@ func (value *ExampleRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if ExampleRef does not comply with the OpenAPI spec.
func (value *ExampleRef) Validate(ctx context.Context) error {
func (value *ExampleRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -123,7 +125,8 @@ func (value *HeaderRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if HeaderRef does not comply with the OpenAPI spec.
func (value *HeaderRef) Validate(ctx context.Context) error {
func (value *HeaderRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -163,7 +166,8 @@ func (value *LinkRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if LinkRef does not comply with the OpenAPI spec.
func (value *LinkRef) Validate(ctx context.Context) error {
func (value *LinkRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -195,7 +199,8 @@ func (value *ParameterRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if ParameterRef does not comply with the OpenAPI spec.
func (value *ParameterRef) Validate(ctx context.Context) error {
func (value *ParameterRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -237,7 +242,8 @@ func (value *ResponseRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if ResponseRef does not comply with the OpenAPI spec.
func (value *ResponseRef) Validate(ctx context.Context) error {
func (value *ResponseRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -279,7 +285,8 @@ func (value *RequestBodyRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if RequestBodyRef does not comply with the OpenAPI spec.
func (value *RequestBodyRef) Validate(ctx context.Context) error {
func (value *RequestBodyRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -328,7 +335,8 @@ func (value *SchemaRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if SchemaRef does not comply with the OpenAPI spec.
func (value *SchemaRef) Validate(ctx context.Context) error {
func (value *SchemaRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down Expand Up @@ -370,7 +378,8 @@ func (value *SecuritySchemeRef) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if SecuritySchemeRef does not comply with the OpenAPI spec.
func (value *SecuritySchemeRef) Validate(ctx context.Context) error {
func (value *SecuritySchemeRef) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)
if v := value.Value; v != nil {
return v.Validate(ctx)
}
Expand Down
4 changes: 3 additions & 1 deletion openapi3/request_body.go
Expand Up @@ -105,7 +105,9 @@ func (requestBody *RequestBody) UnmarshalJSON(data []byte) error {
}

// Validate returns an error if RequestBody does not comply with the OpenAPI spec.
func (requestBody *RequestBody) Validate(ctx context.Context) error {
func (requestBody *RequestBody) Validate(ctx context.Context, opts ...ValidationOption) error {
ctx = WithValidationOptions(ctx, opts...)

if requestBody.Content == nil {
return errors.New("content of the request body is required")
}
Expand Down