validate package - github.com/go-openapi/validate - Go Packages (original) (raw)

Package validate provides methods to validate a swagger specification, as well as tools to validate data against their schema.

This package follows Swagger 2.0. specification (aka OpenAPI 2.0). Reference can be found here: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md.

Validating a specification

Validates a spec document (from JSON or YAML) against the JSON schema for swagger, then checks a number of extra rules that can't be expressed in JSON schema.

Entry points:

Reported as errors:

[x] definition can't declare a property that's already defined by one of its ancestors [x] definition's ancestor can't be a descendant of the same model [x] path uniqueness: each api path should be non-verbatim (account for path param names) unique per method. Validation can be laxed by disabling StrictPathParamUniqueness. [x] each security reference should contain only unique scopes [x] each security scope in a security definition should be unique [x] parameters in path must be unique [x] each path parameter must correspond to a parameter placeholder and vice versa [x] each referenceable definition must have references [x] each definition property listed in the required array must be defined in the properties of the model [x] each parameter should have a unique name and type combination [x] each operation should have only 1 parameter of type body [x] each reference must point to a valid object [x] every default value that is specified must validate against the schema for that property [x] items property is required for all schemas/definitions of type array [x] path parameters must be declared a required [x] headers must not contain $ref [x] schema and property examples provided must validate against their respective object's schema [x] examples provided must validate their schema

Reported as warnings:

[x] path parameters should not contain any of [{,},\w] [x] empty path [x] unused definitions [x] unsupported validation of examples on non-JSON media types [x] examples in response without schema [x] readOnly properties should not be required

Validating a schema

The schema validation toolkit validates data against JSON-schema-draft 04 schema.

It is tested against the full json-schema-testing-suite (https://github.com/json-schema-org/JSON-Schema-Test-Suite), except for the optional part (bignum, ECMA regexp, ...).

It supports the complete JSON-schema vocabulary, including keywords not supported by Swagger (e.g. additionalItems, ...)

Entry points:

Known limitations

With the current version of this package, the following aspects of swagger are not yet supported:

[ ] errors and warnings are not reported with key/line number in spec [ ] default values and examples on responses only support application/json producer type [ ] invalid numeric constraints (such as Minimum, etc..) are not checked except for default and example values [ ] rules for collectionFormat are not implemented [ ] no validation rule for polymorphism support (discriminator) [not done here] [ ] valid js ECMA regexp not supported by Go regexp engine are considered invalid [ ] arbitrary large numbers are not supported: max is math.MaxFloat64

View Source

const (

ArrayDoesNotAllowAdditionalItemsError = "array doesn't allow for additional items"


HasDependencyError = "%q has a dependency on %s"


InvalidSchemaProvidedError = "Invalid schema provided to SchemaValidator: %v"


InvalidTypeConversionError = "invalid type conversion in %s: %v "


MustValidateAtLeastOneSchemaError = "%q must validate at least one schema (anyOf)"


MustValidateOnlyOneSchemaError = "%q must validate one and only one schema (oneOf). %s"


MustValidateAllSchemasError = "%q must validate all the schemas (allOf)%s"


MustNotValidateSchemaError = "%q must not validate the schema (not)"

)

Error messages related to schema validation and returned as results.

View Source

const (

ArrayRequiresItemsError = "%s for %q is a collection without an element type (array requires items definition)"


ArrayInParamRequiresItemsError = "param %q for %q is a collection without an element type (array requires item definition)"

ArrayInHeaderRequiresItemsError = "header %q for %q is a collection without an element type (array requires items definition)"


BothFormDataAndBodyError = "operation %q has both formData and body parameters. Only one such In: type may be used for a given operation"


CannotResolveReferenceError = "could not resolve reference in %s to $ref %s: %v"


CircularAncestryDefinitionError = "definition %q has circular ancestry: %v"


DefaultValueDoesNotValidateError = "default value for %s in %s does not validate its schema"


DefaultValueItemsDoesNotValidateError = "default value for %s.items in %s does not validate its schema"

DefaultValueHeaderDoesNotValidateError = "in operation %q, default value in header %s for %s does not validate its schema"

DefaultValueHeaderItemsDoesNotValidateError = "in operation %q, default value in header.items %s for %s does not validate its schema"


DefaultValueInDoesNotValidateError = "in operation %q, default value in %s does not validate its schema"


DuplicateParamNameError = "duplicate parameter name %q for %q in operation %q"


DuplicatePropertiesError = "definition %q contains duplicate properties: %v"


ExampleValueDoesNotValidateError = "example value for %s in %s does not validate its schema"


ExampleValueItemsDoesNotValidateError = "example value for %s.items in %s does not validate its schema"

ExampleValueHeaderDoesNotValidateError = "in operation %q, example value in header %s for %s does not validate its schema"

ExampleValueHeaderItemsDoesNotValidateError = "in operation %q, example value in header.items %s for %s does not validate its schema"


ExampleValueInDoesNotValidateError = "in operation %q, example value in %s does not validate its schema"


EmptyPathParameterError = "%q contains an empty path parameter"


InvalidDocumentError = "spec validator can only validate spec.Document objects"


InvalidItemsPatternError = "%s for %q has invalid items pattern: %q"


InvalidParameterDefinitionError = "invalid definition for parameter %s in %s in operation %q"


InvalidParameterDefinitionAsSchemaError = "invalid definition as Schema for parameter %s in %s in operation %q"


InvalidPatternError = "pattern %q is invalid in %s"


InvalidPatternInError = "%s in %s has invalid pattern: %q"

InvalidPatternInHeaderError = "in operation %q, header %s for %s has invalid pattern %q: %v"


InvalidPatternInParamError = "operation %q has invalid pattern in param %q: %q"


InvalidReferenceError = "invalid ref %q"


InvalidResponseDefinitionAsSchemaError = "invalid definition as Schema for response %s in %s"


MultipleBodyParamError = "operation %q has more than 1 body param: %v"


NonUniqueOperationIDError = "%q is defined %d times"


NoParameterInPathError = "path param %q has no parameter definition"


NoValidPathErrorOrWarning = "spec has no valid path defined"


NoValidResponseError = "operation %q has no valid response"


PathOverlapError = "path %s overlaps with %s"


PathParamNotInPathError = "path param %q is not present in path %q"


PathParamNotUniqueError = "params in path %q must be unique: %q conflicts with %q"


PathParamRequiredError = "in operation %q,path param %q must be declared as required"

RefNotAllowedInHeaderError = "IMPORTANT!in %q: $ref are not allowed in headers. In context for header %q%s"


RequiredButNotDefinedError = "%q is present in required but not defined as property in definition %q"


SomeParametersBrokenError = "some parameters definitions are broken in %q.%s. Cannot carry on full checks on parameters for operation %s"


UnresolvedReferencesError = "some references could not be resolved in spec. First found: %v"

)

Error messages related to spec validation and returned as results.

View Source

const (

ExamplesWithoutSchemaWarning = "Examples provided without schema in operation %q, %s"


ExamplesMimeNotSupportedWarning = "No validation attempt for examples for media types other than application/json, in operation %q, %s"


PathParamGarbledWarning = "in path %q, param %q contains {,} or white space. Albeit not stricly illegal, this is probably no what you want"


ParamValidationTypeMismatch = "validation keywords of parameter %q in path %q don't match its type %s"


PathStrippedParamGarbledWarning = "path stripped from path parameters %s contains {,} or white space. This is probably no what you want."


ReadOnlyAndRequiredWarning = "Required property %s in %q should not be marked as both required and readOnly"


RefShouldNotHaveSiblingsWarning = "$ref property should have no sibling in %q.%s"


RequiredHasDefaultWarning = "%s in %s has a default value and is required as parameter"


UnusedDefinitionWarning = "definition %q is not used anywhere"


UnusedParamWarning = "parameter %q is not used anywhere"


UnusedResponseWarning = "response %q is not used anywhere"

InvalidObject = "expected an object in %q.%s"

)

Warning messages related to spec validation and returned as results

Additional error codes

AgainstSchema validates the specified data against the provided schema, using a registry of supported formats.

When no pre-parsed *spec.Schema structure is provided, it uses a JSON schema as default. See example.

package main

import ( "encoding/json" "fmt"

"github.com/go-openapi/spec"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"

)

func main() { // Example using encoding/json as unmarshaller var schemaJSON = { "properties": { "name": { "type": "string", "pattern": "^[A-Za-z]+$", "minLength": 1 } }, "patternProperties": { "address-[0-9]+": { "type": "string", "pattern": "^[\\s|a-z]+$" } }, "required": [ "name" ], "additionalProperties": false }

schema := new(spec.Schema)
_ = json.Unmarshal([]byte(schemaJSON), schema)

input := map[string]interface{}{}

// JSON data to validate
inputJSON := `{"name": "Ivan","address-1": "sesame street"}`
_ = json.Unmarshal([]byte(inputJSON), &input)

// strfmt.Default is the registry of recognized formats
err := validate.AgainstSchema(schema, input, strfmt.Default)
if err != nil {
    fmt.Printf("JSON does not validate against schema: %v", err)
} else {
    fmt.Printf("OK")
}

}

Output:

OK

Enum validates if the data is a member of the enum

EnumCase validates if the data is a member of the enum and may respect case-sensitivity for strings

FormatOf validates if a string matches a format in the format registry

func IsValueValidAgainstRange(val interface{}, typeName, format, prefix, path string) error

IsValueValidAgainstRange checks that a numeric value is compatible with the range defined by Type and Format, that is, may be converted without loss.

NOTE: this check is about type capacity and not formal verification such as: 1.0 != 1L

MaxItems validates that there are at most n items in a slice

MaxLength validates a string for maximum length

Maximum validates if a number is smaller than a given maximum

MaximumInt validates if a number is smaller than a given maximum

MaximumNativeType provides native type constraint validation as a facade to various numeric types versions of Maximum constraint check.

Assumes that any possible loss conversion during conversion has been checked beforehand.

NOTE: currently, the max value is marshalled as a float64, no matter what, which means there may be a loss during conversions (e.g. for very large integers)

TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free

MaximumUint validates if a number is smaller than a given maximum

MinItems validates that there are at least n items in a slice

MinLength validates a string for minimum length

Minimum validates if a number is smaller than a given minimum

MinimumInt validates if a number is smaller than a given minimum

MinimumNativeType provides native type constraint validation as a facade to various numeric types versions of Minimum constraint check.

Assumes that any possible loss conversion during conversion has been checked beforehand.

NOTE: currently, the min value is marshalled as a float64, no matter what, which means there may be a loss during conversions (e.g. for very large integers)

TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free

MinimumUint validates if a number is smaller than a given minimum

MultipleOf validates if the provided number is a multiple of the factor

MultipleOfInt validates if the provided integer is a multiple of the factor

MultipleOfNativeType provides native type constraint validation as a facade to various numeric types version of MultipleOf constraint check.

Assumes that any possible loss conversion during conversion has been checked beforehand.

NOTE: currently, the multipleOf factor is marshalled as a float64, no matter what, which means there may be a loss during conversions (e.g. for very large integers)

TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free

MultipleOfUint validates if the provided unsigned integer is a multiple of the factor

Pattern validates a string against a regular expression

ReadOnly validates an interface for readonly

Required validates an interface for requiredness

RequiredNumber validates a number for requiredness

RequiredString validates a string for requiredness

func SetContinueOnErrors(c bool)

SetContinueOnErrors sets global default behavior regarding spec validation errors reporting.

For extended error reporting, you most likely want to set it to true. For faster validation, it's better to give up early when a spec is detected as invalid: set it to false (this is the default).

Setting this mode does NOT affect the validation status.

NOTE: this method affects global defaults. It is not suitable for a concurrent usage.

Spec validates an OpenAPI 2.0 specification document.

Returns an error flattening in a single standard error, all validation messages.

NOTE: SecurityScopes are maps: no need to check uniqueness

package main

import ( "fmt"

"github.com/go-openapi/loads"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"

)

func main() { // Example with high level spec validation call, without showing warnings

// Example with spec file in this repo:
path := "fixtures/validation/valid-ref.json"
doc, err := loads.Spec(path)
if err == nil {
    validate.SetContinueOnErrors(true)         // Set global options
    errs := validate.Spec(doc, strfmt.Default) // Validates spec with default Swagger 2.0 format definitions

    if errs == nil {
        fmt.Println("This spec is valid")
    } else {
        fmt.Printf("This spec has some validation errors: %v\n", errs)
    }
} else {
    fmt.Println("Could not load this spec")
}

}

Output:

This spec is valid

package main

import ( "fmt"

"github.com/go-openapi/loads"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"

)

func main() { // Example with high level spec validation call, without showing warnings

// Example with online spec URL:
url := "http://petstore.swagger.io/v2/swagger.json"
doc, err := loads.JSONSpec(url)
if err == nil {
    validate.SetContinueOnErrors(true)         // Set global options
    errs := validate.Spec(doc, strfmt.Default) // Validates spec with default Swagger 2.0 format definitions

    if errs == nil {
        fmt.Println("This spec is valid")
    } else {
        fmt.Printf("This spec has some validation errors: %v\n", errs)
    }
} else {
    fmt.Println("Could not load this spec:", err)
}

}

Output:

This spec is valid

UniqueItems validates that the provided slice has unique elements

WithOperationRequest returns a new context with operationType request in context value

WithOperationRequest returns a new context with operationType response in context value

type EntityValidator interface { Validate(interface{}) *Result }

An EntityValidator is an interface for things that can validate entities

FieldKey is a pair of an object and a field, usable as a key for a map.

NewFieldKey returns a pair of an object and field usable as a key of a map.

Field returns the underlying field of this key.

func (fk *FieldKey) Object() map[string]interface{}

Object returns the underlying object of this key.

type HeaderValidator struct {

}

A HeaderValidator has very limited subset of validations to apply

NewHeaderValidator creates a new header validator object

func (p *HeaderValidator) Validate(data interface{}) *Result

Validate the value of the header against its schema

ItemKey is a pair of a slice and an index, usable as a key for a map.

func NewItemKey(slice interface{}, i int) ItemKey

NewItemKey returns a pair of a slice and index usable as a key of a map.

func (ik *ItemKey) Index() int

Index returns the underlying index of this key.

func (ik *ItemKey) Slice() []interface{}

Slice returns the underlying slice of this key.

type Option func(*SchemaValidatorOptions)

Option sets optional rules for schema validation

func EnableArrayMustHaveItemsCheck(enable bool) Option

EnableArrayMustHaveItemsCheck activates the swagger rule: an array must have items defined

func EnableObjectArrayTypeCheck(enable bool) Option

EnableObjectArrayTypeCheck activates the swagger rule: an items must be in type: array

func SwaggerSchema(enable bool) Option

SwaggerSchema activates swagger schema validation rules

func WithRecycleValidators(enable bool) Option

WithRecycleValidators saves memory allocations and makes validators available for a single use of Validate() only.

When a validator is recycled, called MUST not call the Validate() method twice.

func WithSkipSchemataResult(enable bool) Option

WithSkipSchemataResult skips the deep audit payload stored in validation Result

type Opts struct { ContinueOnErrors bool

StrictPathParamUniqueness [bool](/builtin#bool)
SkipSchemataResult        [bool](/builtin#bool)

}

Opts specifies validation options for a SpecValidator.

NOTE: other options might be needed, for example a go-swagger specific mode.

A ParamValidator has very limited subset of validations to apply

NewParamValidator creates a new param validator object

func (p *ParamValidator) Validate(data interface{}) *Result

Validate the data against the description of the parameter

type Result struct { Errors []error Warnings []error MatchCount int

}

Result represents a validation result set, composed of errors and warnings.

It is used to keep track of all detected errors and warnings during the validation of a specification.

Matchcount is used to determine which errors are relevant in the case of AnyOf, OneOf schema validation. Results from the validation branch with most matches get eventually selected.

TODO: keep path of key originating the error

func (r *Result) AddErrors(errors ...error)

AddErrors adds errors to this validation result (if not already reported).

Since the same check may be passed several times while exploring the spec structure (via $ref, ...) reported messages are kept unique.

func (r *Result) AddWarnings(warnings ...error)

AddWarnings adds warnings to this validation result (if not already reported).

AsError renders this result as an error interface

TODO: reporting / pretty print with path ordered and indented

func (r *Result) Data() interface{}

Data returns the original data object used for validation. Mutating this renders the result invalid.

FieldSchemata returns the schemata which apply to fields in objects.

func (r *Result) HasErrors() bool

HasErrors returns true when this result is invalid.

Returns false on a nil *Result.

func (r *Result) HasErrorsOrWarnings() bool

HasErrorsOrWarnings returns true when this result contains either errors or warnings.

Returns false on a nil *Result.

func (r *Result) HasWarnings() bool

HasWarnings returns true when this result contains warnings.

Returns false on a nil *Result.

Inc increments the match count

func (r *Result) IsValid() bool

IsValid returns true when this result is valid.

Returns true on a nil *Result.

ItemSchemata returns the schemata which apply to items in slices.

func (r Result) Merge(others ...Result) *Result

Merge merges this result with the other one(s), preserving match counts etc.

func (r Result) MergeAsErrors(others ...Result) *Result

MergeAsErrors merges this result with the other one(s), preserving match counts etc.

Warnings from input are merged as Errors in the returned merged Result.

func (r Result) MergeAsWarnings(others ...Result) *Result

MergeAsWarnings merges this result with the other one(s), preserving match counts etc.

Errors from input are merged as Warnings in the returned merged Result.

RootObjectSchemata returns the schemata which apply to the root object.

SchemaValidator validates data against a JSON schema

NewSchemaValidator creates a new schema validator.

Panics if the provided schema is invalid.

Applies returns true when this schema validator applies

SetPath sets the path for this schema valdiator

func (s *SchemaValidator) Validate(data interface{}) *Result

Validate validates the data against the schema

type SchemaValidatorOptions struct { EnableObjectArrayTypeCheck bool EnableArrayMustHaveItemsCheck bool

}

SchemaValidatorOptions defines optional rules for schema validation

func (svo SchemaValidatorOptions) Options() []Option

Options returns the current set of options

SpecValidator validates a swagger 2.0 spec

NewSpecValidator creates a new swagger spec validator instance

func (s *SpecValidator) SetContinueOnErrors(c bool)

SetContinueOnErrors sets the ContinueOnErrors option for this validator.

func (s SpecValidator) Validate(data interface{}) (Result, *Result)

Validate validates the swagger spec

package main

import ( "fmt"

"github.com/go-openapi/loads"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"

)

func main() { // Example of spec validation call with full result

// Example with online spec URL:
// url := "http://petstore.swagger.io/v2/swagger.json"
// doc, err := loads.JSONSpec(url)

// Example with spec file in this repo:
path := "fixtures/validation/valid-ref.json"
doc, err := loads.Spec(path)
if err == nil {
    validator := validate.NewSpecValidator(doc.Schema(), strfmt.Default)
    validator.SetContinueOnErrors(true)  // Set option for this validator
    result, _ := validator.Validate(doc) // Validates spec with default Swagger 2.0 format definitions
    if result.IsValid() {
        fmt.Println("This spec is valid")
    } else {
        fmt.Println("This spec has some validation errors")
    }
    if result.HasWarnings() {
        fmt.Println("This spec has some validation warnings")
    }
}

}

Output:

This spec is valid This spec has some validation warnings

package main

import ( "fmt"

"github.com/go-openapi/loads"
"github.com/go-openapi/strfmt"
"github.com/go-openapi/validate"

)

func main() { // Example of spec validation call with full result

// Example with online spec URL:
url := "http://petstore.swagger.io/v2/swagger.json"
doc, err := loads.JSONSpec(url)
if err == nil {
    validator := validate.NewSpecValidator(doc.Schema(), strfmt.Default)
    validator.SetContinueOnErrors(true)  // Set option for this validator
    result, _ := validator.Validate(doc) // Validates spec with default Swagger 2.0 format definitions
    if result.IsValid() {
        fmt.Println("This spec is valid")
    } else {
        fmt.Println("This spec has some validation errors")
    }
    if result.HasWarnings() {
        fmt.Println("This spec has some validation warnings")
    }
}

}

Output:

This spec is valid