hack/pin-dependency.sh github.com/go-openapi/validate v0.19.5

This commit is contained in:
Dr. Stefan Schimanski
2019-11-15 13:48:59 +01:00
parent 323639cbba
commit ef88c43c02
188 changed files with 17483 additions and 9558 deletions

5
vendor/github.com/go-openapi/analysis/.codecov.yml generated vendored Normal file
View File

@@ -0,0 +1,5 @@
coverage:
status:
patch:
default:
target: 80%

View File

@@ -4,7 +4,7 @@ linters-settings:
golint:
min-confidence: 0
gocyclo:
min-complexity: 30
min-complexity: 40
maligned:
suggest-new: true
dupl:
@@ -17,5 +17,11 @@ linters:
enable-all: true
disable:
- maligned
- lll
- gochecknoglobals
- gochecknoinits
# scopelint is useful, but also reports false positives
# that unfortunately can't be disabled. So we disable the
# linter rather than changing code that works.
# see: https://github.com/kyoh86/scopelint/issues/4
- scopelint

View File

@@ -1,5 +1,5 @@
# OpenAPI initiative analysis [![Build Status](https://travis-ci.org/go-openapi/analysis.svg?branch=master)](https://travis-ci.org/go-openapi/analysis) [![codecov](https://codecov.io/gh/go-openapi/analysis/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/analysis) [![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
# OpenAPI initiative analysis [![Build Status](https://travis-ci.org/go-openapi/analysis.svg?branch=master)](https://travis-ci.org/go-openapi/analysis) [![Build status](https://ci.appveyor.com/api/projects/status/x377t5o9ennm847o/branch/master?svg=true)](https://ci.appveyor.com/project/casualjim/go-openapi/analysis/branch/master) [![codecov](https://codecov.io/gh/go-openapi/analysis/branch/master/graph/badge.svg)](https://codecov.io/gh/go-openapi/analysis)
[![Slack Status](https://slackin.goswagger.io/badge.svg)](https://slackin.goswagger.io)
[![license](http://img.shields.io/badge/license-Apache%20v2-orange.svg)](https://raw.githubusercontent.com/go-openapi/analysis/master/LICENSE)
[![GoDoc](https://godoc.org/github.com/go-openapi/analysis?status.svg)](http://godoc.org/github.com/go-openapi/analysis)
[![GolangCI](https://golangci.com/badges/github.com/go-openapi/analysis.svg)](https://golangci.com)

View File

@@ -142,38 +142,12 @@ func (p *enumAnalysis) addSchemaEnum(key string, enum []interface{}) {
// or validation etc.
func New(doc *spec.Swagger) *Spec {
a := &Spec{
spec: doc,
consumes: make(map[string]struct{}, 150),
produces: make(map[string]struct{}, 150),
authSchemes: make(map[string]struct{}, 150),
operations: make(map[string]map[string]*spec.Operation, 150),
allSchemas: make(map[string]SchemaRef, 150),
allOfs: make(map[string]SchemaRef, 150),
references: referenceAnalysis{
schemas: make(map[string]spec.Ref, 150),
pathItems: make(map[string]spec.Ref, 150),
responses: make(map[string]spec.Ref, 150),
parameters: make(map[string]spec.Ref, 150),
items: make(map[string]spec.Ref, 150),
headerItems: make(map[string]spec.Ref, 150),
parameterItems: make(map[string]spec.Ref, 150),
allRefs: make(map[string]spec.Ref, 150),
},
patterns: patternAnalysis{
parameters: make(map[string]string, 150),
headers: make(map[string]string, 150),
items: make(map[string]string, 150),
schemas: make(map[string]string, 150),
allPatterns: make(map[string]string, 150),
},
enums: enumAnalysis{
parameters: make(map[string][]interface{}, 150),
headers: make(map[string][]interface{}, 150),
items: make(map[string][]interface{}, 150),
schemas: make(map[string][]interface{}, 150),
allEnums: make(map[string][]interface{}, 150),
},
spec: doc,
references: referenceAnalysis{},
patterns: patternAnalysis{},
enums: enumAnalysis{},
}
a.reset()
a.initialize()
return a
}

33
vendor/github.com/go-openapi/analysis/appveyor.yml generated vendored Normal file
View File

@@ -0,0 +1,33 @@
version: "0.1.{build}"
clone_folder: C:\go-openapi\analysis
shallow_clone: true # for startup speed
pull_requests:
do_not_increment_build_number: true
#skip_tags: true
#skip_branch_with_pr: true
# appveyor.yml
build: off
environment:
GOPATH: c:\gopath
stack: go 1.12
test_script:
- go test -v -timeout 20m ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off
notifications:
- provider: Slack
incoming_webhook: https://hooks.slack.com/services/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
auth_token:
secure: Sf7kZf7ZGbnwWUMpffHwMu5A0cHkLK2MYY32LNTPj4+/3qC3Ghl7+9v4TSLOqOlCwdRNjOGblAq7s+GDJed6/xgRQl1JtCi1klzZNrYX4q01pgTPvvGcwbBkIYgeMaPeIRcK9OZnud7sRXdttozgTOpytps2U6Js32ip7uj5mHSg2ub0FwoSJwlS6dbezZ8+eDhoha0F/guY99BEwx8Bd+zROrT2TFGsSGOFGN6wFc7moCqTHO/YkWib13a2QNXqOxCCVBy/lt76Wp+JkeFppjHlzs/2lP3EAk13RIUAaesdEUHvIHrzCyNJEd3/+KO2DzsWOYfpktd+KBCvgaYOsoo7ubdT3IROeAegZdCgo/6xgCEsmFc9ZcqCfN5yNx2A+BZ2Vwmpws+bQ1E1+B5HDzzaiLcYfG4X2O210QVGVDLWsv1jqD+uPYeHY2WRfh5ZsIUFvaqgUEnwHwrK44/8REAhQavt1QAj5uJpsRd7CkRVPWRNK+yIky+wgbVUFEchRNmS55E7QWf+W4+4QZkQi7vUTMc9nbTUu2Es9NfvfudOpM2wZbn98fjpb/qq/nRv6Bk+ca+7XD5/IgNLMbWp2ouDdzbiHLCOfDUiHiDJhLfFZx9Bwo7ZwfzeOlbrQX66bx7xRKYmOe4DLrXhNcpbsMa8qbfxlZRCmYbubB/Y8h4=
channel: bots
on_build_success: false
on_build_failure: true
on_build_status_changed: true

View File

@@ -140,12 +140,14 @@ func Flatten(opts FlattenOpts) error {
cwd, _ := os.Getwd()
opts.BasePath = filepath.Join(cwd, opts.BasePath)
}
// make sure drive letter on windows is normalized to lower case
u, _ := url.Parse(opts.BasePath)
opts.BasePath = u.String()
opts.flattenContext = newContext()
// recursively expand responses, parameters, path items and items in simple schemas.
// This simplifies the spec and leaves $ref only into schema objects.
//
if err := swspec.ExpandSpec(opts.Swagger(), opts.ExpandOpts(!opts.Expand)); err != nil {
return err
}
@@ -165,8 +167,11 @@ func Flatten(opts FlattenOpts) error {
opts.Spec.reload() // re-analyze
// at this point there are no other references left but schemas
// at this point there are no references left but in schemas
for imported := false; !imported; {
// iteratively import remote references until none left.
// This inlining deals with name conflicts by introducing auto-generated names ("OAIGen")
var err error
if imported, err = importExternalReferences(&opts); err != nil {
return err
@@ -182,8 +187,9 @@ func Flatten(opts FlattenOpts) error {
opts.Spec.reload() // re-analyze
}
// rewrite JSON pointers other than $ref to named definitions
// and attempts to resolve conflicting names
// and attempt to resolve conflicting names whenever possible.
if err := stripPointersAndOAIGen(&opts); err != nil {
return err
}
@@ -195,9 +201,7 @@ func Flatten(opts FlattenOpts) error {
expected[slashpath.Join(definitionsPath, jsonpointer.Escape(k))] = struct{}{}
}
for _, k := range opts.Spec.AllDefinitionReferences() {
if _, ok := expected[k]; ok {
delete(expected, k)
}
delete(expected, k)
}
for k := range expected {
debugLog("removing unused definition %s", slashpath.Base(k))
@@ -362,6 +366,7 @@ func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *A
// rewrite any dependent $ref pointing to this place,
// when not already pointing to a top-level definition.
//
// NOTE: this is important if such referers use arbitrary JSON pointers.
an := New(isn.Spec)
for k, v := range an.references.allRefs {
@@ -373,6 +378,7 @@ func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *A
r.String() == slashpath.Join(definitionsPath, newName) &&
slashpath.Dir(v.String()) != definitionsPath {
debugLog("found a $ref to a rewritten schema: %s points to %s", k, v.String())
// rewrite $ref to the new target
if err := updateRef(isn.Spec, k,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
@@ -383,6 +389,7 @@ func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *A
// NOTE: this extension is currently not used by go-swagger (provided for information only)
sch.AddExtension("x-go-gen-location", genLocation(parts))
// save cloned schema to definitions
saveSchema(isn.Spec, newName, sch)
@@ -408,6 +415,7 @@ func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *A
}
// genLocation indicates from which section of the specification (models or operations) a definition has been created.
//
// This is reflected in the output spec with a "x-go-gen-location" extension. At the moment, this is is provided
// for information only.
func genLocation(parts splitKey) string {
@@ -420,6 +428,7 @@ func genLocation(parts splitKey) string {
return ""
}
// uniqifyName yields a unique name for a definition
func uniqifyName(definitions swspec.Definitions, name string) (string, bool) {
isOAIGen := false
if name == "" {
@@ -432,7 +441,7 @@ func uniqifyName(definitions swspec.Definitions, name string) (string, bool) {
unq := true
for k := range definitions {
if strings.ToLower(k) == strings.ToLower(name) {
if strings.EqualFold(k, name) {
unq = false
break
}
@@ -781,7 +790,14 @@ func cloneSchema(schema *swspec.Schema) (*swspec.Schema, error) {
return &sch, nil
}
// importExternalReferences iteratively digs remote references and imports them into the main schema.
//
// At every iteration, new remotes may be found when digging deeper: they are rebased to the current schema before being imported.
//
// This returns true when no more remote references can be found.
func importExternalReferences(opts *FlattenOpts) (bool, error) {
debugLog("importExternalReferences")
groupedRefs := reverseIndexForSchemaRefs(opts)
sortedRefStr := make([]string, 0, len(groupedRefs))
if opts.flattenContext == nil {
@@ -795,71 +811,110 @@ func importExternalReferences(opts *FlattenOpts) (bool, error) {
sort.Strings(sortedRefStr)
complete := true
for _, refStr := range sortedRefStr {
entry := groupedRefs[refStr]
if !entry.Ref.HasFragmentOnly {
complete = false
var isOAIGen bool
if entry.Ref.HasFragmentOnly {
continue
}
complete = false
var isOAIGen bool
newName := opts.flattenContext.resolved[refStr]
if newName != "" {
// rewrite ref with already resolved external ref (useful for cyclicali refs)
debugLog("resolving known ref [%s] to %s", refStr, newName)
// rewrite the external refs to local ones
for _, key := range entry.Keys {
if err := updateRef(opts.Swagger(), key,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
return false, err
}
}
} else {
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
// resolve to actual schema
sch := new(swspec.Schema)
sch.Ref = entry.Ref
if err := swspec.ExpandSchemaWithBasePath(sch, nil, opts.ExpandOpts(false)); err != nil {
newName := opts.flattenContext.resolved[refStr]
if newName != "" {
// rewrite ref with already resolved external ref (useful for cyclical refs):
// rewrite external refs to local ones
debugLog("resolving known ref [%s] to %s", refStr, newName)
for _, key := range entry.Keys {
if err := updateRef(opts.Swagger(), key,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
return false, err
}
if sch == nil {
return false, fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
}
debugLog("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
// generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name
newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
debugLog("new name for [%s]: %s - with name conflict:%t",
strings.Join(entry.Keys, ", "), newName, isOAIGen)
opts.flattenContext.resolved[refStr] = newName
// rewrite the external refs to local ones
for _, key := range entry.Keys {
if err := updateRef(opts.Swagger(), key,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
return false, err
}
// keep track of created refs
resolved := false
if _, ok := opts.flattenContext.newRefs[key]; ok {
resolved = opts.flattenContext.newRefs[key].resolved
}
opts.flattenContext.newRefs[key] = &newRef{
key: key,
newName: newName,
path: slashpath.Join(definitionsPath, newName),
isOAIGen: isOAIGen,
resolved: resolved,
schema: sch,
}
}
// add the resolved schema to the definitions
saveSchema(opts.Swagger(), newName, sch)
}
} else {
// resolve schemas
debugLog("resolving schema from remote $ref [%s]", refStr)
sch, err := swspec.ResolveRefWithBase(opts.Swagger(), &entry.Ref, opts.ExpandOpts(false))
if err != nil {
return false, fmt.Errorf("could not resolve schema: %v", err)
}
// at this stage only $ref analysis matters
partialAnalyzer := &Spec{
references: referenceAnalysis{},
patterns: patternAnalysis{},
enums: enumAnalysis{},
}
partialAnalyzer.reset()
partialAnalyzer.analyzeSchema("", *sch, "/")
// now rewrite those refs with rebase
for key, ref := range partialAnalyzer.references.allRefs {
if err := updateRef(sch, key, swspec.MustCreateRef(rebaseRef(entry.Ref.String(), ref.String()))); err != nil {
return false, fmt.Errorf("failed to rewrite ref for key %q at %s: %v", key, entry.Ref.String(), err)
}
}
// generate a unique name - isOAIGen means that a naming conflict was resolved by changing the name
newName, isOAIGen = uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
debugLog("new name for [%s]: %s - with name conflict:%t",
strings.Join(entry.Keys, ", "), newName, isOAIGen)
opts.flattenContext.resolved[refStr] = newName
// rewrite the external refs to local ones
for _, key := range entry.Keys {
if err := updateRef(opts.Swagger(), key,
swspec.MustCreateRef(slashpath.Join(definitionsPath, newName))); err != nil {
return false, err
}
// keep track of created refs
resolved := false
if _, ok := opts.flattenContext.newRefs[key]; ok {
resolved = opts.flattenContext.newRefs[key].resolved
}
opts.flattenContext.newRefs[key] = &newRef{
key: key,
newName: newName,
path: slashpath.Join(definitionsPath, newName),
isOAIGen: isOAIGen,
resolved: resolved,
schema: sch,
}
}
// add the resolved schema to the definitions
saveSchema(opts.Swagger(), newName, sch)
}
}
// maintains ref index entries
for k := range opts.flattenContext.newRefs {
r := opts.flattenContext.newRefs[k]
// update tracking with resolved schemas
if r.schema.Ref.String() != "" {
ref := swspec.MustCreateRef(r.path)
sch, err := swspec.ResolveRefWithBase(opts.Swagger(), &ref, opts.ExpandOpts(false))
if err != nil {
return false, fmt.Errorf("could not resolve schema: %v", err)
}
r.schema = sch
}
// update tracking with renamed keys: got a cascade of refs
if r.path != k {
renamed := *r
renamed.key = r.path
opts.flattenContext.newRefs[renamed.path] = &renamed
// indirect ref
r.newName = slashpath.Base(k)
r.schema = swspec.RefSchema(r.path)
r.path = k
r.isOAIGen = strings.Contains(k, "OAIGen")
}
}
return complete, nil
}
@@ -868,20 +923,77 @@ type refRevIdx struct {
Keys []string
}
// rebaseRef rebase a remote ref relative to a base ref.
//
// NOTE: does not support JSONschema ID for $ref (we assume we are working with swagger specs here).
//
// NOTE(windows):
// * refs are assumed to have been normalized with drive letter lower cased (from go-openapi/spec)
// * "/ in paths may appear as escape sequences
func rebaseRef(baseRef string, ref string) string {
debugLog("rebasing ref: %s onto %s", ref, baseRef)
baseRef, _ = url.PathUnescape(baseRef)
ref, _ = url.PathUnescape(ref)
if baseRef == "" || baseRef == "." || strings.HasPrefix(baseRef, "#") {
return ref
}
parts := strings.Split(ref, "#")
baseParts := strings.Split(baseRef, "#")
baseURL, _ := url.Parse(baseParts[0])
if strings.HasPrefix(ref, "#") {
if baseURL.Host == "" {
return strings.Join([]string{baseParts[0], parts[1]}, "#")
}
return strings.Join([]string{baseParts[0], parts[1]}, "#")
}
refURL, _ := url.Parse(parts[0])
if refURL.Host != "" || filepath.IsAbs(parts[0]) {
// not rebasing an absolute path
return ref
}
// there is a relative path
var basePath string
if baseURL.Host != "" {
// when there is a host, standard URI rules apply (with "/")
baseURL.Path = slashpath.Dir(baseURL.Path)
baseURL.Path = slashpath.Join(baseURL.Path, "/"+parts[0])
return baseURL.String()
}
// this is a local relative path
// basePart[0] and parts[0] are local filesystem directories/files
basePath = filepath.Dir(baseParts[0])
relPath := filepath.Join(basePath, string(filepath.Separator)+parts[0])
if len(parts) > 1 {
return strings.Join([]string{relPath, parts[1]}, "#")
}
return relPath
}
// normalizePath renders absolute path on remote file refs
//
// NOTE(windows):
// * refs are assumed to have been normalized with drive letter lower cased (from go-openapi/spec)
// * "/ in paths may appear as escape sequences
func normalizePath(ref swspec.Ref, opts *FlattenOpts) (normalizedPath string) {
if ref.HasFragmentOnly || filepath.IsAbs(ref.String()) {
normalizedPath = ref.String()
uri, _ := url.PathUnescape(ref.String())
if ref.HasFragmentOnly || filepath.IsAbs(uri) {
normalizedPath = uri
return
}
refURL, _ := url.Parse(ref.String())
refURL, _ := url.Parse(uri)
if refURL.Host != "" {
normalizedPath = ref.String()
normalizedPath = uri
return
}
parts := strings.Split(ref.String(), "#")
parts := strings.Split(uri, "#")
// BasePath, parts[0] are local filesystem directories, guaranteed to be absolute at this stage
parts[0] = filepath.Join(filepath.Dir(opts.BasePath), parts[0])
normalizedPath = strings.Join(parts, "#")
return
@@ -935,7 +1047,16 @@ func saveSchema(spec *swspec.Swagger, name string, schema *swspec.Schema) {
}
// getPointerFromKey retrieves the content of the JSON pointer "key"
func getPointerFromKey(spec *swspec.Swagger, key string) (string, interface{}, error) {
func getPointerFromKey(spec interface{}, key string) (string, interface{}, error) {
switch spec.(type) {
case *swspec.Schema:
case *swspec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
}
if key == "#/" {
return "", spec, nil
}
// unescape chars in key, e.g. "{}" from path params
pth, _ := internal.PathUnescape(key[1:])
ptr, err := jsonpointer.New(pth)
@@ -952,7 +1073,13 @@ func getPointerFromKey(spec *swspec.Swagger, key string) (string, interface{}, e
}
// getParentFromKey retrieves the container of the JSON pointer "key"
func getParentFromKey(spec *swspec.Swagger, key string) (string, string, interface{}, error) {
func getParentFromKey(spec interface{}, key string) (string, string, interface{}, error) {
switch spec.(type) {
case *swspec.Schema:
case *swspec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
}
// unescape chars in key, e.g. "{}" from path params
pth, _ := internal.PathUnescape(key[1:])
@@ -971,7 +1098,13 @@ func getParentFromKey(spec *swspec.Swagger, key string) (string, string, interfa
}
// updateRef replaces a ref by another one
func updateRef(spec *swspec.Swagger, key string, ref swspec.Ref) error {
func updateRef(spec interface{}, key string, ref swspec.Ref) error {
switch spec.(type) {
case *swspec.Schema:
case *swspec.Swagger:
default:
panic("unexpected type used in getPointerFromKey")
}
debugLog("updating ref for %s with %s", key, ref.String())
pth, value, err := getPointerFromKey(spec, key)
if err != nil {
@@ -1165,6 +1298,7 @@ func stripPointersAndOAIGen(opts *FlattenOpts) error {
// iterate as pointer or OAIGen resolution may introduce inline schemas or pointers
for hasIntroducedPointerOrInline {
if !opts.Minimal {
opts.Spec.reload() // re-analyze
if err := nameInlinedSchemas(opts); err != nil {
return err
}
@@ -1178,60 +1312,123 @@ func stripPointersAndOAIGen(opts *FlattenOpts) error {
if hasIntroducedPointerOrInline, ers = stripOAIGen(opts); ers != nil {
return ers
}
opts.Spec.reload() // re-analyze
}
return nil
}
// stripOAIGen strips the spec from unnecessary OAIGen constructs, initially created to dedupe flattened definitions.
//
// A dedupe is deemed unnecessary whenever:
// - the only conflict is with its (single) parent: OAIGen is merged into its parent
// - the only conflict is with its (single) parent: OAIGen is merged into its parent (reinlining)
// - there is a conflict with multiple parents: merge OAIGen in first parent, the rewrite other parents to point to
// the first parent.
//
// This function returns a true bool whenever it re-inlined a complex schema, so the caller may chose to iterate
// flattening again.
//
// NOTE: the OAIGen definition cannot be itself a $ref.
// pointer and name resolution again.
func stripOAIGen(opts *FlattenOpts) (bool, error) {
debugLog("stripOAIGen")
replacedWithComplex := false
for k, v := range opts.Spec.references.allRefs {
// figure out referers of OAIGen definitions
for _, r := range opts.flattenContext.newRefs {
if r.isOAIGen && !r.resolved && r.path == v.String() { // bail on already resolved entries (avoid looping)
// figure out referers of OAIGen definitions
for _, r := range opts.flattenContext.newRefs {
if !r.isOAIGen || r.resolved { // bail on already resolved entries (avoid looping)
continue
}
for k, v := range opts.Spec.references.allRefs {
if r.path != v.String() {
continue
}
found := false
for _, p := range r.parents {
if p == k {
found = true
break
}
}
if !found {
r.parents = append(r.parents, k)
}
}
}
for _, r := range opts.flattenContext.newRefs {
if r.isOAIGen && len(r.parents) >= 1 && r.schema.Ref.String() == "" {
for k := range opts.flattenContext.newRefs {
r := opts.flattenContext.newRefs[k]
//debugLog("newRefs[%s]: isOAIGen: %t, resolved: %t, name: %s, path:%s, #parents: %d, parents: %v, ref: %s",
// k, r.isOAIGen, r.resolved, r.newName, r.path, len(r.parents), r.parents, r.schema.Ref.String())
if r.isOAIGen && len(r.parents) >= 1 {
pr := r.parents
sort.Strings(pr)
// rewrite first parent schema in lexicographical order
debugLog("rewrite first parent %s with schema", pr[0])
debugLog("rewrite first parent in lex order %s with schema", pr[0])
if err := updateRefWithSchema(opts.Swagger(), pr[0], r.schema); err != nil {
return false, err
}
if pa, ok := opts.flattenContext.newRefs[pr[0]]; ok && pa.isOAIGen {
// update parent in ref index entry
debugLog("update parent entry: %s", pr[0])
pa.schema = r.schema
pa.resolved = false
replacedWithComplex = true
}
// rewrite other parents to point to first parent
if len(pr) > 1 {
for _, p := range pr[1:] {
replacingRef := swspec.MustCreateRef(pr[0])
// Set complex when replacing ref is an anonymous jsonpointer: further processing may be required
// set complex when replacing ref is an anonymous jsonpointer: further processing may be required
replacedWithComplex = replacedWithComplex ||
slashpath.Dir(replacingRef.String()) != definitionsPath
debugLog("rewrite parent with ref: %s", replacingRef.String())
// NOTE: it is possible at this stage to introduce json pointers (to non-definitions places).
// Those are stripped later on.
if err := updateRef(opts.Swagger(), p, replacingRef); err != nil {
return false, err
}
if pa, ok := opts.flattenContext.newRefs[p]; ok && pa.isOAIGen {
// update parent in ref index
debugLog("update parent entry: %s", p)
pa.schema = r.schema
pa.resolved = false
replacedWithComplex = true
}
}
}
// remove OAIGen definition
debugLog("removing definition %s", slashpath.Base(r.path))
delete(opts.Swagger().Definitions, slashpath.Base(r.path))
// propagate changes in ref index for keys which have this one as a parent
for kk, value := range opts.flattenContext.newRefs {
if kk == k || !value.isOAIGen || value.resolved {
continue
}
found := false
newParents := make([]string, 0, len(value.parents))
for _, parent := range value.parents {
switch {
case parent == r.path:
found = true
parent = pr[0]
case strings.HasPrefix(parent, r.path+"/"):
found = true
parent = slashpath.Join(pr[0], strings.TrimPrefix(parent, r.path))
}
newParents = append(newParents, parent)
}
if found {
value.parents = newParents
}
}
// mark naming conflict as resolved
debugLog("marking naming conflict resolved for key: %s", r.key)
opts.flattenContext.newRefs[r.key].isOAIGen = false
opts.flattenContext.newRefs[r.key].resolved = true
@@ -1241,12 +1438,14 @@ func stripOAIGen(opts *FlattenOpts) (bool, error) {
if err != nil {
return false, err
}
debugLog("re-inline schema: parent: %s, %t", pr[0], isAnalyzedAsComplex(asch))
debugLog("re-inlined schema: parent: %s, %t", pr[0], isAnalyzedAsComplex(asch))
replacedWithComplex = replacedWithComplex ||
!(slashpath.Dir(pr[0]) == definitionsPath) && isAnalyzedAsComplex(asch)
}
}
}
debugLog("replacedWithComplex: %t", replacedWithComplex)
opts.Spec.reload() // re-analyze
return replacedWithComplex, nil
}
@@ -1338,6 +1537,14 @@ func namePointers(opts *FlattenOpts) error {
debugLog("namePointers at %s for %s", key, v.Ref.String())
// qualify the expanded schema
/*
if key == "#/paths/~1some~1where~1{id}/get/parameters/1/items" {
// DEBUG
//func getPointerFromKey(spec interface{}, key string) (string, interface{}, error) {
k, res, err := getPointerFromKey(namer.Spec, key)
debugLog("k = %s, res=%#v, err=%v", k, res, err)
}
*/
asch, ers := Schema(SchemaOpts{Schema: v.Schema, Root: opts.Swagger(), BasePath: opts.BasePath})
if ers != nil {
return fmt.Errorf("schema analysis [%s]: %v", key, ers)

View File

@@ -1,13 +1,13 @@
module github.com/go-openapi/analysis
require (
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect
github.com/go-openapi/errors v0.19.2 // indirect
github.com/go-openapi/jsonpointer v0.19.2
github.com/go-openapi/jsonpointer v0.19.3
github.com/go-openapi/loads v0.19.0
github.com/go-openapi/spec v0.19.2
github.com/go-openapi/strfmt v0.19.0
github.com/go-openapi/swag v0.19.2
github.com/go-openapi/spec v0.19.3
github.com/go-openapi/strfmt v0.19.3
github.com/go-openapi/swag v0.19.5
github.com/stretchr/testify v1.3.0
go.mongodb.org/mongo-driver v1.1.1 // indirect
)
go 1.13

View File

@@ -10,8 +10,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
@@ -19,20 +17,30 @@ github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.2 h1:clPGfBnJohokno0e+d7hs6Yocrzjlgz6EsQSDncCRnE=
github.com/go-openapi/strfmt v0.19.2/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -45,6 +53,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
@@ -55,6 +65,12 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -62,6 +78,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -27,7 +27,7 @@ import (
// collisions are avoided by appending "Mixin<N>" but only if
// needed.
//
// The following parts of primary are never modified by merging:
// The following parts of primary are subject to merge, filling empty details
// - Info
// - BasePath
// - Host
@@ -57,6 +57,8 @@ func Mixin(primary *spec.Swagger, mixins ...*spec.Swagger) []string {
initPrimary(primary)
for i, m := range mixins {
skipped = append(skipped, mergeSwaggerProps(primary, m)...)
skipped = append(skipped, mergeConsumes(primary, m)...)
skipped = append(skipped, mergeProduces(primary, m)...)
@@ -220,10 +222,10 @@ func mergeResponses(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
}
primary.Responses[k] = v
}
return
return skipped
}
func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) []string {
for _, v := range m.Consumes {
found := false
for _, vv := range primary.Consumes {
@@ -238,10 +240,10 @@ func mergeConsumes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
}
primary.Consumes = append(primary.Consumes, v)
}
return
return []string{}
}
func mergeProduces(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
func mergeProduces(primary *spec.Swagger, m *spec.Swagger) []string {
for _, v := range m.Produces {
found := false
for _, vv := range primary.Produces {
@@ -256,7 +258,7 @@ func mergeProduces(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
}
primary.Produces = append(primary.Produces, v)
}
return
return []string{}
}
func mergeTags(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
@@ -279,7 +281,7 @@ func mergeTags(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
return
}
func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) []string {
for _, v := range m.Schemes {
found := false
for _, vv := range primary.Schemes {
@@ -294,6 +296,95 @@ func mergeSchemes(primary *spec.Swagger, m *spec.Swagger) (skipped []string) {
}
primary.Schemes = append(primary.Schemes, v)
}
return []string{}
}
func mergeSwaggerProps(primary *spec.Swagger, m *spec.Swagger) []string {
var skipped []string
primary.Extensions, skipped = mergeExtensions(primary.Extensions, m.Extensions)
// merging details in swagger top properties
if primary.Host == "" {
primary.Host = m.Host
}
if primary.BasePath == "" {
primary.BasePath = m.BasePath
}
if primary.Info == nil {
primary.Info = m.Info
} else if m.Info != nil {
var sk []string
primary.Info.Extensions, sk = mergeExtensions(primary.Info.Extensions, m.Info.Extensions)
skipped = append(skipped, sk...)
if primary.Info.Description == "" {
primary.Info.Description = m.Info.Description
}
if primary.Info.Title == "" {
primary.Info.Description = m.Info.Description
}
if primary.Info.TermsOfService == "" {
primary.Info.TermsOfService = m.Info.TermsOfService
}
if primary.Info.Version == "" {
primary.Info.Version = m.Info.Version
}
if primary.Info.Contact == nil {
primary.Info.Contact = m.Info.Contact
} else if m.Info.Contact != nil {
if primary.Info.Contact.Name == "" {
primary.Info.Contact.Name = m.Info.Contact.Name
}
if primary.Info.Contact.URL == "" {
primary.Info.Contact.URL = m.Info.Contact.URL
}
if primary.Info.Contact.Email == "" {
primary.Info.Contact.Email = m.Info.Contact.Email
}
}
if primary.Info.License == nil {
primary.Info.License = m.Info.License
} else if m.Info.License != nil {
if primary.Info.License.Name == "" {
primary.Info.License.Name = m.Info.License.Name
}
if primary.Info.License.URL == "" {
primary.Info.License.URL = m.Info.License.URL
}
}
}
if primary.ExternalDocs == nil {
primary.ExternalDocs = m.ExternalDocs
} else if m.ExternalDocs != nil {
if primary.ExternalDocs.Description == "" {
primary.ExternalDocs.Description = m.ExternalDocs.Description
}
if primary.ExternalDocs.URL == "" {
primary.ExternalDocs.URL = m.ExternalDocs.URL
}
}
return skipped
}
func mergeExtensions(primary spec.Extensions, m spec.Extensions) (result spec.Extensions, skipped []string) {
if primary == nil {
result = m
return
}
if m == nil {
result = primary
return
}
result = primary
for k, v := range m {
if _, found := primary[k]; found {
skipped = append(skipped, k)
continue
}
primary[k] = v
}
return
}

View File

@@ -40,10 +40,7 @@ func Schema(opts SchemaOpts) (*AnalyzedSchema, error) {
return nil, err
}
if err := a.inferTuple(); err != nil {
// NOTE(fredbi): currently, inferTuple() never returns an error
return nil, err
}
a.inferTuple()
if err := a.inferFromRef(); err != nil {
return nil, err
@@ -112,21 +109,19 @@ func (a *AnalyzedSchema) inferFromRef() error {
if err != nil {
return err
}
if sch != nil {
// NOTE(fredbi): currently the only cause for errors in
rsch, err := Schema(SchemaOpts{
Schema: sch,
Root: a.root,
BasePath: a.basePath,
})
if err != nil {
// NOTE(fredbi): currently the only cause for errors is
// unresolved ref. Since spec.ExpandSchema() expands the
// schema recursively, there is no chance to get there,
// until we add more causes for error in this schema analysis.
rsch, err := Schema(SchemaOpts{
Schema: sch,
Root: a.root,
BasePath: a.basePath,
})
if err != nil {
return err
}
a.inherits(rsch)
return err
}
a.inherits(rsch)
}
return nil
}
@@ -198,11 +193,10 @@ func (a *AnalyzedSchema) inferArray() error {
return nil
}
func (a *AnalyzedSchema) inferTuple() error {
func (a *AnalyzedSchema) inferTuple() {
tuple := a.hasItems && a.schema.Items.Schemas != nil
a.IsTuple = tuple && !a.hasAdditionalItems
a.IsTupleWithExtra = tuple && a.hasAdditionalItems
return nil
}
func (a *AnalyzedSchema) inferBaseType() {

View File

@@ -3,8 +3,10 @@ module github.com/go-openapi/jsonreference
require (
github.com/PuerkitoBio/purell v1.1.1
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/go-openapi/jsonpointer v0.19.2
github.com/go-openapi/jsonpointer v0.19.3
github.com/stretchr/testify v1.3.0
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 // indirect
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect
golang.org/x/text v0.3.2 // indirect
)
go 1.13

View File

@@ -7,8 +7,12 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -16,6 +20,8 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -24,6 +30,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=

View File

@@ -1,9 +1,11 @@
module github.com/go-openapi/loads
require (
github.com/go-openapi/analysis v0.19.2
github.com/go-openapi/spec v0.19.2
github.com/go-openapi/swag v0.19.2
github.com/go-openapi/analysis v0.19.5
github.com/go-openapi/spec v0.19.3
github.com/go-openapi/swag v0.19.5
github.com/stretchr/testify v1.3.0
gopkg.in/yaml.v2 v2.2.2
gopkg.in/yaml.v2 v2.2.4
)
go 1.13

View File

@@ -10,42 +10,50 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
github.com/go-openapi/analysis v0.19.0 h1:sYEyyO7OKQvJX0z4OyHWoGt0uLuALxB/ZJ4Jb3I6KNU=
github.com/go-openapi/analysis v0.19.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
@@ -56,6 +64,12 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -63,6 +77,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -73,7 +89,10 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -4,20 +4,12 @@ go:
- 1.11.x
- 1.12.x
install:
- go get -u github.com/axw/gocov/gocov
- go get -u gopkg.in/matm/v1/gocov-html
- go get -u github.com/cee-dub/go-junit-report
- go get -u github.com/stretchr/testify/assert
- go get -u gopkg.in/yaml.v2
- go get -u github.com/go-openapi/analysis
- go get -u github.com/go-openapi/errors
- go get -u github.com/go-openapi/loads
- go get -u github.com/go-openapi/strfmt
- go get -u github.com/go-openapi/validate
- go get -u github.com/docker/go-units
- GO111MODULE=off go get -u gotest.tools/gotestsum
env:
- GO111MODULE=on
language: go
notifications:
slack:
secure: EmObnQuM9Mw8J9vpFaKKHqSMN4Wsr/A9+v7ewAD5cEhA0T1P4m7MbJMiJOhxUhj/X+BFh2DamW+P2lT8mybj5wg8wnkQ2BteKA8Tawi6f9PRw2NRheO8tAi8o/npLnlmet0kc93mn+oLuqHw36w4+j5mkOl2FghkfGiUVhwrhkCP7KXQN+3TU87e+/HzQumlJ3nsE+6terVxkH3PmaUTsS5ONaODZfuxFpfb7RsoEl3skHf6d+tr+1nViLxxly7558Nc33C+W1mr0qiEvMLZ+kJ/CpGWBJ6CUJM3jm6hNe2eMuIPwEK2hxZob8c7n22VPap4K6a0bBRoydoDXaba+2sD7Ym6ivDO/DVyL44VeBBLyIiIBylDGQdZH+6SoWm90Qe/i7tnY/T5Ao5igT8f3cfQY1c3EsTfqmlDfrhmACBmwSlgkdVBLTprHL63JMY24LWmh4jhxsmMRZhCL4dze8su1w6pLN/pD1pGHtKYCEVbdTmaM3PblNRFf12XB7qosmQsgUndH4Vq3bTbU0s1pKjeDhRyLvFzvR0TBbo0pDLEoF1A/i5GVFWa7yLZNUDudQERRh7qv/xBl2excIaQ1sV4DSVm7bAE9l6Kp+yeHQJW2uN6Y3X8wu9gB9nv9l5HBze7wh8KE6PyWAOLYYqZg9/sAtsv/2GcQqXcKFF1zcA=
script:
- ./hack/coverage
- gotestsum -f short-verbose -- -race -timeout=20m -coverprofile=coverage.txt -covermode=atomic ./...

View File

@@ -109,6 +109,10 @@ func ByteStreamProducer(opts ...byteStreamOpt) Producer {
}
defer close()
if rc, ok := data.(io.ReadCloser); ok {
defer rc.Close()
}
if rdr, ok := data.(io.Reader); ok {
_, err := io.Copy(writer, rdr)
return err

View File

@@ -1,25 +1,16 @@
module github.com/go-openapi/runtime
require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/docker/go-units v0.3.3
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 // indirect
github.com/go-openapi/analysis v0.18.0
github.com/go-openapi/errors v0.18.0
github.com/go-openapi/jsonpointer v0.18.0 // indirect
github.com/go-openapi/jsonreference v0.18.0 // indirect
github.com/go-openapi/loads v0.18.0
github.com/go-openapi/spec v0.18.0
github.com/go-openapi/strfmt v0.18.0
github.com/go-openapi/swag v0.18.0
github.com/go-openapi/validate v0.18.0
github.com/google/uuid v1.1.1 // indirect
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe // indirect
github.com/stretchr/objx v0.1.1 // indirect
github.com/docker/go-units v0.4.0
github.com/go-openapi/analysis v0.19.2
github.com/go-openapi/errors v0.19.2
github.com/go-openapi/loads v0.19.2
github.com/go-openapi/spec v0.19.2
github.com/go-openapi/strfmt v0.19.0
github.com/go-openapi/swag v0.19.2
github.com/go-openapi/validate v0.19.2
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576 // indirect
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 // indirect
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54 // indirect
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56 // indirect
golang.org/x/tools v0.0.0-20190617190820-da514acc4774 // indirect
gopkg.in/yaml.v2 v2.2.2
)

View File

@@ -6,11 +6,15 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -19,46 +23,72 @@ github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpR
github.com/go-openapi/analysis v0.17.2 h1:eYp14J1o8TTSCzndHBtsNuckikV1PfZOSnx4BcBeu0c=
github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.17.2 h1:azEQ8Fnx0jmtFF2fxsnmd6I0x6rsweUF63qqSO1NmKk=
github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.17.2 h1:3ekBy41gar/iJi2KSh/au/PrC2vpLr85upF/UZmm3W0=
github.com/go-openapi/jsonpointer v0.17.2/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.17.2 h1:lF3z7AH8dd0IKXc1zEBi1dj0B4XgVb5cVjn39dCK3Ls=
github.com/go-openapi/jsonreference v0.17.2/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.17.2 h1:tEXYu6Xc0pevpzzQx5ghrMN9F7IVpN/+u4iD3rkYE5o=
github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.17.2 h1:eb2NbuCnoe8cWAxhtK6CfMWUYmiFEZJ9Hx3Z2WRwJ5M=
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.17.2 h1:2KDns36DMHXG9/iYkOjiX+/8fKK9GCU5ELZ+J6qcRVA=
github.com/go-openapi/strfmt v0.17.2/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.17.2 h1:K/ycE/XTUDFltNHSO32cGRUhrVGJD64o8WgAIZNyc3k=
github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.17.2 h1:lwFfiS4sv5DvOrsYDsYq4N7UU8ghXiYtPJ+VcQnC3Xg=
github.com/go-openapi/validate v0.17.2/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2 h1:ky5l57HjyVRrsJfd2+Ro5Z9PjGuKbsmftwyMtk8H7js=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe h1:W/GaMY0y69G4cFlmsC6B9sbuo2fP8OFP1ABjt4kPz+w=
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
@@ -66,20 +96,36 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53 h1:kcXqo9vE6fsZY5X5Rd7R1l7fTgnWaDCVmln65REefiE=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -15,6 +15,7 @@
package runtime
import (
"bufio"
"io"
"net/http"
"strings"
@@ -42,7 +43,68 @@ func AllowsBody(r *http.Request) bool {
// HasBody returns true if this method needs a content-type
func HasBody(r *http.Request) bool {
return len(r.TransferEncoding) > 0 || r.ContentLength > 0
// happy case: we have a content length set
if r.ContentLength > 0 {
return true
}
if r.Header.Get(http.CanonicalHeaderKey("content-length")) != "" {
// in this case, no Transfer-Encoding should be present
// we have a header set but it was explicitly set to 0, so we assume no body
return false
}
rdr := newPeekingReader(r.Body)
r.Body = rdr
return rdr.HasContent()
}
func newPeekingReader(r io.ReadCloser) *peekingReader {
if r == nil {
return nil
}
return &peekingReader{
underlying: bufio.NewReader(r),
orig: r,
}
}
type peekingReader struct {
underlying interface {
Buffered() int
Peek(int) ([]byte, error)
Read([]byte) (int, error)
}
orig io.ReadCloser
}
func (p *peekingReader) HasContent() bool {
if p == nil {
return false
}
if p.underlying.Buffered() > 0 {
return true
}
b, err := p.underlying.Peek(1)
if err != nil {
return false
}
return len(b) > 0
}
func (p *peekingReader) Read(d []byte) (int, error) {
if p == nil {
return 0, io.EOF
}
return p.underlying.Read(d)
}
func (p *peekingReader) Close() error {
p.underlying = nil
if p.orig != nil {
return p.orig.Close()
}
return nil
}
// JSONRequest creates a new http request with json headers set

View File

@@ -39,6 +39,12 @@ func TextConsumer() Consumer {
}
b := buf.Bytes()
// If the buffer is empty, no need to unmarshal it, which causes a panic.
if len(b) == 0 {
data = ""
return nil
}
if tu, ok := data.(encoding.TextUnmarshaler); ok {
err := tu.UnmarshalText(b)
if err != nil {

View File

@@ -21,7 +21,7 @@ import (
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %v", name, err)
}
var buf bytes.Buffer
@@ -29,7 +29,7 @@ func bindataRead(data []byte, name string) ([]byte, error) {
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
return nil, fmt.Errorf("read %q: %v", name, err)
}
if clErr != nil {
return nil, err
@@ -85,7 +85,7 @@ func jsonschemaDraft04JSON() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4357, mode: os.FileMode(436), modTime: time.Unix(1540282154, 0)}
info := bindataFileInfo{name: "jsonschema-draft-04.json", size: 4357, mode: os.FileMode(0644), modTime: time.Unix(1567900649, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xe1, 0x48, 0x9d, 0xb, 0x47, 0x55, 0xf0, 0x27, 0x93, 0x30, 0x25, 0x91, 0xd3, 0xfc, 0xb8, 0xf0, 0x7b, 0x68, 0x93, 0xa8, 0x2a, 0x94, 0xf2, 0x48, 0x95, 0xf8, 0xe4, 0xed, 0xf1, 0x1b, 0x82, 0xe2}}
return a, nil
}
@@ -105,7 +105,7 @@ func v2SchemaJSON() (*asset, error) {
return nil, err
}
info := bindataFileInfo{name: "v2/schema.json", size: 40249, mode: os.FileMode(436), modTime: time.Unix(1540282154, 0)}
info := bindataFileInfo{name: "v2/schema.json", size: 40249, mode: os.FileMode(0644), modTime: time.Unix(1567900649, 0)}
a := &asset{bytes: bytes, info: info, digest: [32]uint8{0xcb, 0x25, 0x27, 0xe8, 0x46, 0xae, 0x22, 0xc4, 0xf4, 0x8b, 0x1, 0x32, 0x4d, 0x1f, 0xf8, 0xdf, 0x75, 0x15, 0xc8, 0x2d, 0xc7, 0xed, 0xe, 0x7e, 0x0, 0x75, 0xc0, 0xf9, 0xd2, 0x1f, 0x75, 0x57}}
return a, nil
}

View File

@@ -1,14 +1,17 @@
module github.com/go-openapi/spec
require (
github.com/go-openapi/jsonpointer v0.19.2
github.com/go-openapi/jsonpointer v0.19.3
github.com/go-openapi/jsonreference v0.19.2
github.com/go-openapi/swag v0.19.2
github.com/go-openapi/swag v0.19.5
github.com/kr/pty v1.1.5 // indirect
github.com/stretchr/objx v0.2.0 // indirect
github.com/stretchr/testify v1.3.0
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 // indirect
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f // indirect
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59 // indirect
gopkg.in/yaml.v2 v2.2.2
)
go 1.13

View File

@@ -13,6 +13,8 @@ github.com/go-openapi/jsonpointer v0.19.0 h1:FTUMcX77w5rQkClIzDtTxvn6Bsa894CcrzN
github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.0 h1:BqWKpV1dFd+AuiKlgtddwVIFQsuMpxfBDBHGfM2yNpk=
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
@@ -21,6 +23,8 @@ github.com/go-openapi/swag v0.17.0 h1:iqrgMg7Q7SvtbWLlltPrkMs0UBJI6oTSs79JFRUi88
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
@@ -31,6 +35,8 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -47,6 +53,8 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=

View File

@@ -160,6 +160,7 @@ func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error)
if !fromCache {
b, err := r.loadDoc(normalized)
if err != nil {
debugLog("unable to load the document: %v", err)
return nil, url.URL{}, false, err
}

View File

@@ -27,3 +27,4 @@ issues:
text: "should be .*ObjectID"
linters:
- golint

View File

@@ -1,20 +1,15 @@
after_success:
- bash <(curl -s https://codecov.io/bash)
go:
- '1.9'
- 1.10.x
- 1.11.x
- 1.12.x
install:
- go get -u github.com/stretchr/testify/assert
- go get -u github.com/google/uuid
- go get -u github.com/asaskevich/govalidator
- go get -u github.com/mailru/easyjson
- go get -u github.com/go-openapi/errors
- go get -u github.com/mitchellh/mapstructure
- go get -u github.com/globalsign/mgo/bson
- GO111MODULE=off go get -u gotest.tools/gotestsum
language: go
env:
- GO111MODULE=on
notifications:
slack:
secure: zE5AtIYTpYfQPnTzP+EaQPN7JKtfFAGv6PrJqoIZLOXa8B6zGb6+J1JRNNxWi7faWbyJOxa4FSSsuPsKZMycUK6wlLFIdhDxwqeo7Ew8r6rdZKdfUHQggfNS9wO79ARoNYUDHtmnaBUS+eWSM1YqSc4i99QxyyfuURLOeAaA/q14YbdlTlaw3lrZ0qT92ot1FnVGNOx064zuHtFeUf+jAVRMZ6Q3rvqllwIlPszE6rmHGXBt2VoJxRaBetdwd7FgkcYw9FPXKHhadwC7/75ZAdmxIukhxNMw4Tr5NuPcqNcnbYLenDP7B3lssGVIrP4BRSqekS1d/tqvdvnnFWHMwrNCkSnSc065G5+qWTlXKAemIclgiXXqE2furBNLm05MDdG8fn5epS0UNarkjD+zX336RiqwBlOX4KbF+vPyqcO98CsN0lnd+H6loc9reiTHs37orFFpQ+309av9be2GGsHUsRB9ssIyrewmhAccOmkRtr2dVTZJNFQwa5Kph5TNJuTjnZEwG/xUkEX2YSfwShOsb062JWiflV6PJdnl80pc9Tn7D5sO5Bf9DbijGRJwwP+YiiJtwtr+vsvS+n4sM0b5eqm4UoRo+JJO8ffoJtHS7ItuyRbVQCwEPJ4221WLcf5PquEEDdAPwR+K4Gj8qTXqTDdxOiES1xFUKVgmzhI=
script:
- ./hack/coverage
- gotestsum -f short-verbose -- -race -coverprofile=coverage.txt -covermode=atomic ./...

View File

@@ -16,11 +16,11 @@ go_library(
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/asaskevich/govalidator:go_default_library",
"//vendor/github.com/globalsign/mgo/bson:go_default_library",
"//vendor/github.com/go-openapi/errors:go_default_library",
"//vendor/github.com/mailru/easyjson/jlexer:go_default_library",
"//vendor/github.com/mailru/easyjson/jwriter:go_default_library",
"//vendor/github.com/mitchellh/mapstructure:go_default_library",
"//vendor/go.mongodb.org/mongo-driver/bson:go_default_library",
"//vendor/go.mongodb.org/mongo-driver/bson/bsontype:go_default_library",
"//vendor/go.mongodb.org/mongo-driver/bson/primitive:go_default_library",
],
)

View File

@@ -16,12 +16,12 @@ package strfmt
import (
"database/sql/driver"
"errors"
"fmt"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/bsontype"
bsonprim "go.mongodb.org/mongo-driver/bson/primitive"
)
func init() {
@@ -32,27 +32,45 @@ func init() {
// IsBSONObjectID returns true when the string is a valid BSON.ObjectId
func IsBSONObjectID(str string) bool {
return bson.IsObjectIdHex(str)
_, err := bsonprim.ObjectIDFromHex(str)
return err == nil
}
// ObjectId represents a BSON object ID (alias to github.com/globalsign/mgo/bson.ObjectId)
// ObjectId represents a BSON object ID (alias to go.mongodb.org/mongo-driver/bson/primitive.ObjectID)
//
// swagger:strfmt bsonobjectid
type ObjectId bson.ObjectId
type ObjectId bsonprim.ObjectID
// NewObjectId creates a ObjectId from a Hex String
func NewObjectId(hex string) ObjectId {
return ObjectId(bson.ObjectIdHex(hex))
oid, err := bsonprim.ObjectIDFromHex(hex)
if err != nil {
panic(err)
}
return ObjectId(oid)
}
// MarshalText turns this instance into text
func (id *ObjectId) MarshalText() ([]byte, error) {
return []byte(bson.ObjectId(*id).Hex()), nil
func (id ObjectId) MarshalText() ([]byte, error) {
oid := bsonprim.ObjectID(id)
if oid == bsonprim.NilObjectID {
return nil, nil
}
return []byte(oid.Hex()), nil
}
// UnmarshalText hydrates this instance from text
func (id *ObjectId) UnmarshalText(data []byte) error { // validation is performed later on
*id = ObjectId(bson.ObjectIdHex(string(data)))
if len(data) == 0 {
*id = ObjectId(bsonprim.NilObjectID)
return nil
}
oidstr := string(data)
oid, err := bsonprim.ObjectIDFromHex(oidstr)
if err != nil {
return err
}
*id = ObjectId(oid)
return nil
}
@@ -72,58 +90,63 @@ func (id *ObjectId) Scan(raw interface{}) error {
}
// Value converts a value to a database driver value
func (id *ObjectId) Value() (driver.Value, error) {
return driver.Value(string(*id)), nil
func (id ObjectId) Value() (driver.Value, error) {
return driver.Value(bsonprim.ObjectID(id).Hex()), nil
}
func (id *ObjectId) String() string {
return string(*id)
func (id ObjectId) String() string {
return bsonprim.ObjectID(id).String()
}
// MarshalJSON returns the ObjectId as JSON
func (id *ObjectId) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
id.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the ObjectId to a easyjson.Writer
func (id *ObjectId) MarshalEasyJSON(w *jwriter.Writer) {
w.String(bson.ObjectId(*id).Hex())
func (id ObjectId) MarshalJSON() ([]byte, error) {
return bsonprim.ObjectID(id).MarshalJSON()
}
// UnmarshalJSON sets the ObjectId from JSON
func (id *ObjectId) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
id.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the ObjectId from a easyjson.Lexer
func (id *ObjectId) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
*id = NewObjectId(data)
}
}
// GetBSON returns the hex representation of the ObjectId as a bson.M{} map.
func (id *ObjectId) GetBSON() (interface{}, error) {
return bson.M{"data": bson.ObjectId(*id).Hex()}, nil
}
// SetBSON sets the ObjectId from raw bson data
func (id *ObjectId) SetBSON(raw bson.Raw) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
var obj bsonprim.ObjectID
if err := obj.UnmarshalJSON(data); err != nil {
return err
}
*id = ObjectId(obj)
return nil
}
if data, ok := m["data"].(string); ok {
*id = NewObjectId(data)
return nil
// MarshalBSON renders the object id as a BSON document
func (id ObjectId) MarshalBSON() ([]byte, error) {
return bson.Marshal(bson.M{"data": bsonprim.ObjectID(id)})
}
// UnmarshalBSON reads the objectId from a BSON document
func (id *ObjectId) UnmarshalBSON(data []byte) error {
var obj struct {
Data bsonprim.ObjectID
}
if err := bson.Unmarshal(data, &obj); err != nil {
return err
}
*id = ObjectId(obj.Data)
return nil
}
return errors.New("couldn't unmarshal bson raw value as ObjectId")
// MarshalBSONValue is an interface implemented by types that can marshal themselves
// into a BSON document represented as bytes. The bytes returned must be a valid
// BSON document if the error is nil.
func (id ObjectId) MarshalBSONValue() (bsontype.Type, []byte, error) {
oid := bsonprim.ObjectID(id)
return bsontype.ObjectID, oid[:], nil
}
// UnmarshalBSONValue is an interface implemented by types that can unmarshal a
// BSON value representation of themselves. The BSON bytes and type can be
// assumed to be valid. UnmarshalBSONValue must copy the BSON value bytes if it
// wishes to retain the data after returning.
func (id *ObjectId) UnmarshalBSONValue(tpe bsontype.Type, data []byte) error {
var oid bsonprim.ObjectID
copy(oid[:], data)
*id = ObjectId(oid)
return nil
}
// DeepCopyInto copies the receiver and writes its value into out.

View File

@@ -16,13 +16,12 @@ package strfmt
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
"go.mongodb.org/mongo-driver/bson"
)
func init() {
@@ -96,14 +95,7 @@ func (d Date) Value() (driver.Value, error) {
// MarshalJSON returns the Date as JSON
func (d Date) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
d.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the Date to a easyjson.Writer
func (d Date) MarshalEasyJSON(w *jwriter.Writer) {
w.String(time.Time(d).Format(RFC3339FullDate))
return json.Marshal(time.Time(d).Format(RFC3339FullDate))
}
// UnmarshalJSON sets the Date from JSON
@@ -111,42 +103,38 @@ func (d *Date) UnmarshalJSON(data []byte) error {
if string(data) == jsonNull {
return nil
}
l := jlexer.Lexer{Data: data}
d.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the Date from a easyjson.Lexer
func (d *Date) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
tt, err := time.Parse(RFC3339FullDate, data)
if err != nil {
in.AddError(err)
return
}
*d = Date(tt)
var strdate string
if err := json.Unmarshal(data, &strdate); err != nil {
return err
}
tt, err := time.Parse(RFC3339FullDate, strdate)
if err != nil {
return err
}
*d = Date(tt)
return nil
}
// GetBSON returns the Date as a bson.M{} map.
func (d *Date) GetBSON() (interface{}, error) {
return bson.M{"data": d.String()}, nil
func (d Date) MarshalBSON() ([]byte, error) {
return bson.Marshal(bson.M{"data": d.String()})
}
// SetBSON sets the Date from raw bson data
func (d *Date) SetBSON(raw bson.Raw) error {
func (d *Date) UnmarshalBSON(data []byte) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
if err := bson.Unmarshal(data, &m); err != nil {
return err
}
if data, ok := m["data"].(string); ok {
rd, err := time.Parse(RFC3339FullDate, data)
if err != nil {
return err
}
*d = Date(rd)
return err
return nil
}
return errors.New("couldn't unmarshal bson raw value as Date")
return errors.New("couldn't unmarshal bson bytes value as Date")
}
// DeepCopyInto copies the receiver and writes its value into out.

File diff suppressed because it is too large Load Diff

View File

@@ -16,6 +16,7 @@ package strfmt
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"regexp"
@@ -23,9 +24,7 @@ import (
"strings"
"time"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
"go.mongodb.org/mongo-driver/bson"
)
func init() {
@@ -153,53 +152,47 @@ func (d Duration) String() string {
// MarshalJSON returns the Duration as JSON
func (d Duration) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
d.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the Duration to a easyjson.Writer
func (d Duration) MarshalEasyJSON(w *jwriter.Writer) {
w.String(time.Duration(d).String())
return json.Marshal(time.Duration(d).String())
}
// UnmarshalJSON sets the Duration from JSON
func (d *Duration) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
d.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the Duration from a easyjson.Lexer
func (d *Duration) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
tt, err := ParseDuration(data)
if err != nil {
in.AddError(err)
return
}
*d = Duration(tt)
}
}
// GetBSON returns the Duration a bson.M{} map.
func (d *Duration) GetBSON() (interface{}, error) {
return bson.M{"data": int64(*d)}, nil
}
// SetBSON sets the Duration from raw bson data
func (d *Duration) SetBSON(raw bson.Raw) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
return err
}
if data, ok := m["data"].(int64); ok {
*d = Duration(data)
if string(data) == jsonNull {
return nil
}
return errors.New("couldn't unmarshal bson raw value as Duration")
var dstr string
if err := json.Unmarshal(data, &dstr); err != nil {
return err
}
tt, err := ParseDuration(dstr)
if err != nil {
return err
}
*d = Duration(tt)
return nil
}
func (d Duration) MarshalBSON() ([]byte, error) {
return bson.Marshal(bson.M{"data": d.String()})
}
func (d *Duration) UnmarshalBSON(data []byte) error {
var m bson.M
if err := bson.Unmarshal(data, &m); err != nil {
return err
}
if data, ok := m["data"].(string); ok {
rd, err := ParseDuration(data)
if err != nil {
return err
}
*d = Duration(rd)
return nil
}
return errors.New("couldn't unmarshal bson bytes value as Date")
}
// DeepCopyInto copies the receiver and writes its value into out.

View File

@@ -225,7 +225,7 @@ func (f *defaultFormats) DelByName(name string) bool {
return false
}
// DelByType removes the specified format, returns true when an item was actually removed
// DelByFormat removes the specified format, returns true when an item was actually removed
func (f *defaultFormats) DelByFormat(strfmt Format) bool {
f.Lock()
defer f.Unlock()

View File

@@ -1,13 +1,13 @@
module github.com/go-openapi/strfmt
require (
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb
github.com/go-openapi/errors v0.17.0
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a
github.com/go-openapi/errors v0.19.2
github.com/go-stack/stack v1.8.0 // indirect
github.com/google/go-cmp v0.3.0 // indirect
github.com/google/uuid v1.1.1
github.com/kr/pretty v0.1.0 // indirect
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329
github.com/mitchellh/mapstructure v1.1.2
github.com/stretchr/testify v1.2.2
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect
github.com/stretchr/testify v1.3.0
github.com/tidwall/pretty v1.0.0 // indirect
go.mongodb.org/mongo-driver v1.0.3
)

View File

@@ -1,25 +1,25 @@
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb h1:D4uzjWwKYQ5XnAvUbuvHW93esHg7F8N/OYeBBcJoTr0=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/errors v0.17.0 h1:g5DzIh94VpuR/dd6Ff8KqyHNnw7yBa2xSHIPPzjRDUo=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=

View File

@@ -16,15 +16,14 @@ package strfmt
import (
"database/sql/driver"
"encoding/json"
"errors"
"fmt"
"regexp"
"strings"
"time"
"github.com/globalsign/mgo/bson"
"github.com/mailru/easyjson/jlexer"
"github.com/mailru/easyjson/jwriter"
"go.mongodb.org/mongo-driver/bson"
)
func init() {
@@ -56,12 +55,14 @@ const (
RFC3339Millis = "2006-01-02T15:04:05.000Z07:00"
// RFC3339Micro represents a ISO8601 format to micro instead of to nano
RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00"
// ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone)
ISO8601LocalTime = "2006-01-02T15:04:05"
// DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6
DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$`
)
var (
dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano}
dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime}
rxDateTime = regexp.MustCompile(DateTimePattern)
// MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds)
MarshalFormat = RFC3339Millis
@@ -79,7 +80,6 @@ func ParseDateTime(data string) (DateTime, error) {
lastError = err
continue
}
lastError = nil
return DateTime(dd), nil
}
return DateTime{}, lastError
@@ -144,54 +144,47 @@ func (t DateTime) Value() (driver.Value, error) {
// MarshalJSON returns the DateTime as JSON
func (t DateTime) MarshalJSON() ([]byte, error) {
var w jwriter.Writer
t.MarshalEasyJSON(&w)
return w.BuildBytes()
}
// MarshalEasyJSON writes the DateTime to a easyjson.Writer
func (t DateTime) MarshalEasyJSON(w *jwriter.Writer) {
w.String(time.Time(t).Format(MarshalFormat))
return json.Marshal(time.Time(t).Format(MarshalFormat))
}
// UnmarshalJSON sets the DateTime from JSON
func (t *DateTime) UnmarshalJSON(data []byte) error {
l := jlexer.Lexer{Data: data}
t.UnmarshalEasyJSON(&l)
return l.Error()
}
// UnmarshalEasyJSON sets the DateTime from a easyjson.Lexer
func (t *DateTime) UnmarshalEasyJSON(in *jlexer.Lexer) {
if data := in.String(); in.Ok() {
tt, err := ParseDateTime(data)
if err != nil {
in.AddError(err)
return
}
*t = tt
if string(data) == jsonNull {
return nil
}
var tstr string
if err := json.Unmarshal(data, &tstr); err != nil {
return err
}
tt, err := ParseDateTime(tstr)
if err != nil {
return err
}
*t = tt
return nil
}
// GetBSON returns the DateTime as a bson.M{} map.
func (t *DateTime) GetBSON() (interface{}, error) {
return bson.M{"data": t.String()}, nil
func (t DateTime) MarshalBSON() ([]byte, error) {
return bson.Marshal(bson.M{"data": t.String()})
}
// SetBSON sets the DateTime from raw bson data
func (t *DateTime) SetBSON(raw bson.Raw) error {
func (t *DateTime) UnmarshalBSON(data []byte) error {
var m bson.M
if err := raw.Unmarshal(&m); err != nil {
if err := bson.Unmarshal(data, &m); err != nil {
return err
}
if data, ok := m["data"].(string); ok {
var err error
*t, err = ParseDateTime(data)
return err
rd, err := ParseDateTime(data)
if err != nil {
return err
}
*t = rd
return nil
}
return errors.New("couldn't unmarshal bson raw value as Duration")
return errors.New("couldn't unmarshal bson bytes value as Date")
}
// DeepCopyInto copies the receiver and writes its value into out.

View File

@@ -4,17 +4,25 @@ linters-settings:
golint:
min-confidence: 0
gocyclo:
min-complexity: 25
min-complexity: 50
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
min-occurrences: 3
linters:
enable-all: true
disable:
- maligned
- lll
- godox
- gocognit
- whitespace
- wsl
- funlen
- gochecknoglobals
- gochecknoinits
- scopelint

View File

@@ -33,14 +33,8 @@ func (d *defaultValidator) resetVisited() {
d.visitedSchemas = map[string]bool{}
}
// beingVisited asserts a schema is being visited
func (d *defaultValidator) beingVisited(path string) {
d.visitedSchemas[path] = true
}
// isVisited tells if a path has already been visited
func (d *defaultValidator) isVisited(path string) bool {
found := d.visitedSchemas[path]
func isVisited(path string, visitedSchemas map[string]bool) bool {
found := visitedSchemas[path]
if !found {
// search for overlapping paths
frags := strings.Split(path, ".")
@@ -70,6 +64,16 @@ func (d *defaultValidator) isVisited(path string) bool {
return found
}
// beingVisited asserts a schema is being visited
func (d *defaultValidator) beingVisited(path string) {
d.visitedSchemas[path] = true
}
// isVisited tells if a path has already been visited
func (d *defaultValidator) isVisited(path string) bool {
return isVisited(path, d.visitedSchemas)
}
// Validate validates the default values declared in the swagger spec
func (d *defaultValidator) Validate() (errs *Result) {
errs = new(Result)
@@ -89,64 +93,60 @@ func (d *defaultValidator) validateDefaultValueValidAgainstSchema() *Result {
s := d.SpecValidator
for method, pathItem := range s.analyzer.Operations() {
if pathItem != nil { // Safeguard
for path, op := range pathItem {
// parameters
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
if param.Default != nil && param.Required {
res.AddWarnings(requiredHasDefaultMsg(param.Name, param.In))
}
for path, op := range pathItem {
// parameters
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
if param.Default != nil && param.Required {
res.AddWarnings(requiredHasDefaultMsg(param.Name, param.In))
}
// reset explored schemas to get depth-first recursive-proof exploration
d.resetVisited()
// reset explored schemas to get depth-first recursive-proof exploration
d.resetVisited()
// Check simple parameters first
// default values provided must validate against their inline definition (no explicit schema)
if param.Default != nil && param.Schema == nil {
// check param default value is valid
red := NewParamValidator(&param, s.KnownFormats).Validate(param.Default)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
// Recursively follows Items and Schemas
if param.Items != nil {
red := d.validateDefaultValueItemsAgainstSchema(param.Name, param.In, &param, param.Items)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueItemsDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
if param.Schema != nil {
// Validate default value against schema
red := d.validateDefaultValueSchemaAgainstSchema(param.Name, param.In, param.Schema)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
// Check simple parameters first
// default values provided must validate against their inline definition (no explicit schema)
if param.Default != nil && param.Schema == nil {
// check param default value is valid
red := NewParamValidator(&param, s.KnownFormats).Validate(param.Default)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
if op.Responses != nil {
if op.Responses.Default != nil {
// Same constraint on default Response
res.Merge(d.validateDefaultInResponse(op.Responses.Default, "default", path, 0, op.ID))
}
// Same constraint on regular Responses
if op.Responses.StatusCodeResponses != nil { // Safeguard
for code, r := range op.Responses.StatusCodeResponses {
res.Merge(d.validateDefaultInResponse(&r, "response", path, code, op.ID))
}
}
} else {
// Empty op.ID means there is no meaningful operation: no need to report a specific message
if op.ID != "" {
res.AddErrors(noValidResponseMsg(op.ID))
// Recursively follows Items and Schemas
if param.Items != nil {
red := d.validateDefaultValueItemsAgainstSchema(param.Name, param.In, &param, param.Items)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueItemsDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
if param.Schema != nil {
// Validate default value against schema
red := d.validateDefaultValueSchemaAgainstSchema(param.Name, param.In, param.Schema)
if red.HasErrorsOrWarnings() {
res.AddErrors(defaultValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
}
if op.Responses != nil {
if op.Responses.Default != nil {
// Same constraint on default Response
res.Merge(d.validateDefaultInResponse(op.Responses.Default, jsonDefault, path, 0, op.ID))
}
// Same constraint on regular Responses
if op.Responses.StatusCodeResponses != nil { // Safeguard
for code, r := range op.Responses.StatusCodeResponses {
res.Merge(d.validateDefaultInResponse(&r, "response", path, code, op.ID))
}
}
} else if op.ID != "" {
// Empty op.ID means there is no meaningful operation: no need to report a specific message
res.AddErrors(noValidResponseMsg(op.ID))
}
}
}
@@ -170,6 +170,7 @@ func (d *defaultValidator) validateDefaultInResponse(resp *spec.Response, respon
responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode)
// nolint: dupl
if response.Headers != nil { // Safeguard
for nm, h := range response.Headers {
// reset explored schemas to get depth-first recursive-proof exploration
@@ -223,7 +224,7 @@ func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path, in stri
s := d.SpecValidator
if schema.Default != nil {
res.Merge(NewSchemaValidator(schema, s.spec.Spec(), path+".default", s.KnownFormats).Validate(schema.Default))
res.Merge(NewSchemaValidator(schema, s.spec.Spec(), path+".default", s.KnownFormats, SwaggerSchema(true)).Validate(schema.Default))
}
if schema.Items != nil {
if schema.Items.Schema != nil {
@@ -260,6 +261,8 @@ func (d *defaultValidator) validateDefaultValueSchemaAgainstSchema(path, in stri
return res
}
// TODO: Temporary duplicated code. Need to refactor with examples
// nolint: dupl
func (d *defaultValidator) validateDefaultValueItemsAgainstSchema(path, in string, root interface{}, items *spec.Items) *Result {
res := new(Result)
s := d.SpecValidator

View File

@@ -16,7 +16,6 @@ package validate
import (
"fmt"
"strings"
"github.com/go-openapi/spec"
)
@@ -39,34 +38,7 @@ func (ex *exampleValidator) beingVisited(path string) {
// isVisited tells if a path has already been visited
func (ex *exampleValidator) isVisited(path string) bool {
found := ex.visitedSchemas[path]
if !found {
// search for overlapping paths
frags := strings.Split(path, ".")
if len(frags) < 2 {
// shortcut exit on smaller paths
return found
}
last := len(frags) - 1
var currentFragStr, parent string
for i := range frags {
if i == 0 {
currentFragStr = frags[last]
} else {
currentFragStr = strings.Join([]string{frags[last-i], currentFragStr}, ".")
}
if i < last {
parent = strings.Join(frags[0:last-i], ".")
} else {
parent = ""
}
if strings.HasSuffix(parent, currentFragStr) {
found = true
break
}
}
}
return found
return isVisited(path, ex.visitedSchemas)
}
// Validate validates the example values declared in the swagger spec
@@ -97,64 +69,60 @@ func (ex *exampleValidator) validateExampleValueValidAgainstSchema() *Result {
s := ex.SpecValidator
for method, pathItem := range s.analyzer.Operations() {
if pathItem != nil { // Safeguard
for path, op := range pathItem {
// parameters
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
for path, op := range pathItem {
// parameters
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
// As of swagger 2.0, Examples are not supported in simple parameters
// However, it looks like it is supported by go-openapi
// As of swagger 2.0, Examples are not supported in simple parameters
// However, it looks like it is supported by go-openapi
// reset explored schemas to get depth-first recursive-proof exploration
ex.resetVisited()
// reset explored schemas to get depth-first recursive-proof exploration
ex.resetVisited()
// Check simple parameters first
// default values provided must validate against their inline definition (no explicit schema)
if param.Example != nil && param.Schema == nil {
// check param default value is valid
red := NewParamValidator(&param, s.KnownFormats).Validate(param.Example)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In))
res.MergeAsWarnings(red)
}
}
// Recursively follows Items and Schemas
if param.Items != nil {
red := ex.validateExampleValueItemsAgainstSchema(param.Name, param.In, &param, param.Items)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueItemsDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
if param.Schema != nil {
// Validate example value against schema
red := ex.validateExampleValueSchemaAgainstSchema(param.Name, param.In, param.Schema)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
// Check simple parameters first
// default values provided must validate against their inline definition (no explicit schema)
if param.Example != nil && param.Schema == nil {
// check param default value is valid
red := NewParamValidator(&param, s.KnownFormats).Validate(param.Example)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In))
res.MergeAsWarnings(red)
}
}
if op.Responses != nil {
if op.Responses.Default != nil {
// Same constraint on default Response
res.Merge(ex.validateExampleInResponse(op.Responses.Default, "default", path, 0, op.ID))
}
// Same constraint on regular Responses
if op.Responses.StatusCodeResponses != nil { // Safeguard
for code, r := range op.Responses.StatusCodeResponses {
res.Merge(ex.validateExampleInResponse(&r, "response", path, code, op.ID))
}
}
} else {
// Empty op.ID means there is no meaningful operation: no need to report a specific message
if op.ID != "" {
res.AddErrors(noValidResponseMsg(op.ID))
// Recursively follows Items and Schemas
if param.Items != nil {
red := ex.validateExampleValueItemsAgainstSchema(param.Name, param.In, &param, param.Items)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueItemsDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
if param.Schema != nil {
// Validate example value against schema
red := ex.validateExampleValueSchemaAgainstSchema(param.Name, param.In, param.Schema)
if red.HasErrorsOrWarnings() {
res.AddWarnings(exampleValueDoesNotValidateMsg(param.Name, param.In))
res.Merge(red)
}
}
}
if op.Responses != nil {
if op.Responses.Default != nil {
// Same constraint on default Response
res.Merge(ex.validateExampleInResponse(op.Responses.Default, jsonDefault, path, 0, op.ID))
}
// Same constraint on regular Responses
if op.Responses.StatusCodeResponses != nil { // Safeguard
for code, r := range op.Responses.StatusCodeResponses {
res.Merge(ex.validateExampleInResponse(&r, "response", path, code, op.ID))
}
}
} else if op.ID != "" {
// Empty op.ID means there is no meaningful operation: no need to report a specific message
res.AddErrors(noValidResponseMsg(op.ID))
}
}
}
@@ -178,6 +146,7 @@ func (ex *exampleValidator) validateExampleInResponse(resp *spec.Response, respo
responseName, responseCodeAsStr := responseHelp.responseMsgVariants(responseType, responseCode)
// nolint: dupl
if response.Headers != nil { // Safeguard
for nm, h := range response.Headers {
// reset explored schemas to get depth-first recursive-proof exploration
@@ -222,7 +191,7 @@ func (ex *exampleValidator) validateExampleInResponse(resp *spec.Response, respo
if response.Examples != nil {
if response.Schema != nil {
if example, ok := response.Examples["application/json"]; ok {
res.MergeAsWarnings(NewSchemaValidator(response.Schema, s.spec.Spec(), path, s.KnownFormats).Validate(example))
res.MergeAsWarnings(NewSchemaValidator(response.Schema, s.spec.Spec(), path+".examples", s.KnownFormats, SwaggerSchema(true)).Validate(example))
} else {
// TODO: validate other media types too
res.AddWarnings(examplesMimeNotSupportedMsg(operationID, responseName))
@@ -244,7 +213,7 @@ func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path, in str
res := new(Result)
if schema.Example != nil {
res.MergeAsWarnings(NewSchemaValidator(schema, s.spec.Spec(), path+".example", s.KnownFormats).Validate(schema.Example))
res.MergeAsWarnings(NewSchemaValidator(schema, s.spec.Spec(), path+".example", s.KnownFormats, SwaggerSchema(true)).Validate(schema.Example))
}
if schema.Items != nil {
if schema.Items.Schema != nil {
@@ -281,6 +250,8 @@ func (ex *exampleValidator) validateExampleValueSchemaAgainstSchema(path, in str
return res
}
// TODO: Temporary duplicated code. Need to refactor with examples
// nolint: dupl
func (ex *exampleValidator) validateExampleValueItemsAgainstSchema(path, in string, root interface{}, items *spec.Items) *Result {
res := new(Result)
s := ex.SpecValidator

View File

@@ -37,19 +37,15 @@ func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool {
if source == nil {
return false
}
switch source.(type) {
switch source := source.(type) {
case *spec.Items:
it := source.(*spec.Items)
return kind == reflect.String && f.KnownFormats.ContainsName(it.Format)
return kind == reflect.String && f.KnownFormats.ContainsName(source.Format)
case *spec.Parameter:
par := source.(*spec.Parameter)
return kind == reflect.String && f.KnownFormats.ContainsName(par.Format)
return kind == reflect.String && f.KnownFormats.ContainsName(source.Format)
case *spec.Schema:
sch := source.(*spec.Schema)
return kind == reflect.String && f.KnownFormats.ContainsName(sch.Format)
return kind == reflect.String && f.KnownFormats.ContainsName(source.Format)
case *spec.Header:
hdr := source.(*spec.Header)
return kind == reflect.String && f.KnownFormats.ContainsName(hdr.Format)
return kind == reflect.String && f.KnownFormats.ContainsName(source.Format)
}
return false
}

View File

@@ -1,14 +1,20 @@
module github.com/go-openapi/validate
require (
github.com/go-openapi/analysis v0.19.2
github.com/go-openapi/analysis v0.19.5
github.com/go-openapi/errors v0.19.2
github.com/go-openapi/jsonpointer v0.19.2
github.com/go-openapi/loads v0.19.2
github.com/go-openapi/runtime v0.19.0
github.com/go-openapi/spec v0.19.2
github.com/go-openapi/strfmt v0.19.0
github.com/go-openapi/swag v0.19.2
github.com/stretchr/testify v1.3.0
gopkg.in/yaml.v2 v2.2.2
github.com/go-openapi/jsonpointer v0.19.3
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/go-openapi/loads v0.19.4
github.com/go-openapi/runtime v0.19.4
github.com/go-openapi/spec v0.19.3
github.com/go-openapi/strfmt v0.19.3
github.com/go-openapi/swag v0.19.5
github.com/mailru/easyjson v0.7.0 // indirect
github.com/stretchr/testify v1.4.0
github.com/vektah/gqlparser v1.1.2
go.mongodb.org/mongo-driver v1.1.2 // indirect
gopkg.in/yaml.v2 v2.2.4
)
go 1.13

View File

@@ -3,6 +3,9 @@ github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tN
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
@@ -10,6 +13,7 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
@@ -18,6 +22,8 @@ github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpR
github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
github.com/go-openapi/analysis v0.19.2 h1:ophLETFestFZHk3ji7niPEL4d466QjW+0Tdg5VyDq7E=
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5 h1:8b2ZgKfKIUTVQpTb77MoRDIMEIwvDVw40o3aOXdfYzI=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
@@ -26,32 +32,53 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds
github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.0 h1:wCOBNscACI8L93tt5tvB2zOMkJ098XCw3fP0BY2ybDA=
github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
github.com/go-openapi/loads v0.19.2 h1:rf5ArTHmIJxyV5Oiks+Su0mUens1+AjpkPoWr5xFRcI=
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.3 h1:jwIoahqCmaA5OBoc/B+1+Mu2L0Gr8xYQnbeyQEo/7b0=
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
github.com/go-openapi/loads v0.19.4 h1:5I4CCSqoWzT+82bBkNIvmLc0UOsoKKQ4Fz+3VxOB7SY=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
github.com/go-openapi/runtime v0.19.0 h1:sU6pp4dSV2sGlNKKyHxZzi1m1kG4WnYtWcJ+HYbygjE=
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.4 h1:csnOgcgAiuGoM/Po7PEpKDoNulCcF3FGbSnbHfxgjMI=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE=
github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.18.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
github.com/go-openapi/strfmt v0.19.3 h1:eRfyY5SkaNJCAwmmMcADjY31ow9+N7MCLW7oRkbsINA=
github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6+bY1AVL9LU=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@@ -65,26 +92,48 @@ github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/vektah/gqlparser v1.1.2 h1:ZsyLGn7/7jDNI+y4SEhI4yAxRChlv15pUHMjijT+e68=
github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw=
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.1 h1:Sq1fR+0c58RME5EoqKdjkiQAmPjmfHlZOoRI6fTUOcs=
go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.mongodb.org/mongo-driver v1.1.2 h1:jxcFYjlkl8xaERsgLo+RNquI0epW6zuy/ZRQs6jnrFA=
go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980 h1:dfGZHvZk057jK2MCeWus/TowKpJ8y4AmooUzdBSR9GU=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -94,10 +143,14 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -26,8 +26,67 @@ import (
"github.com/go-openapi/spec"
)
const swaggerBody = "body"
const objectType = "object"
const (
swaggerBody = "body"
swaggerExample = "example"
swaggerExamples = "examples"
)
const (
objectType = "object"
arrayType = "array"
stringType = "string"
integerType = "integer"
numberType = "number"
booleanType = "boolean"
fileType = "file"
nullType = "null"
)
const (
jsonProperties = "properties"
jsonItems = "items"
jsonType = "type"
//jsonSchema = "schema"
jsonDefault = "default"
)
const (
stringFormatDate = "date"
stringFormatDateTime = "date-time"
stringFormatPassword = "password"
stringFormatByte = "byte"
//stringFormatBinary = "binary"
stringFormatCreditCard = "creditcard"
stringFormatDuration = "duration"
stringFormatEmail = "email"
stringFormatHexColor = "hexcolor"
stringFormatHostname = "hostname"
stringFormatIPv4 = "ipv4"
stringFormatIPv6 = "ipv6"
stringFormatISBN = "isbn"
stringFormatISBN10 = "isbn10"
stringFormatISBN13 = "isbn13"
stringFormatMAC = "mac"
stringFormatBSONObjectID = "bsonobjectid"
stringFormatRGBColor = "rgbcolor"
stringFormatSSN = "ssn"
stringFormatURI = "uri"
stringFormatUUID = "uuid"
stringFormatUUID3 = "uuid3"
stringFormatUUID4 = "uuid4"
stringFormatUUID5 = "uuid5"
integerFormatInt32 = "int32"
integerFormatInt64 = "int64"
integerFormatUInt32 = "uint32"
integerFormatUInt64 = "uint64"
numberFormatFloat32 = "float32"
numberFormatFloat64 = "float64"
numberFormatFloat = "float"
numberFormatDouble = "double"
)
// Helpers available at the package level
var (
@@ -205,7 +264,8 @@ func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation
res := new(Result)
simpleZero := spec.SimpleSchema{}
// Try to explain why... best guess
if pr.In == swaggerBody && (pr.SimpleSchema != simpleZero && pr.SimpleSchema.Type != objectType) {
switch {
case pr.In == swaggerBody && (pr.SimpleSchema != simpleZero && pr.SimpleSchema.Type != objectType):
if isRef {
// Most likely, a $ref with a sibling is an unwanted situation: in itself this is a warning...
// but we detect it because of the following error:
@@ -213,13 +273,12 @@ func (h *paramHelper) checkExpandedParam(pr *spec.Parameter, path, in, operation
res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
}
res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
} else if pr.In != swaggerBody && pr.Schema != nil {
case pr.In != swaggerBody && pr.Schema != nil:
if isRef {
res.AddWarnings(refShouldNotHaveSiblingsMsg(path, operation))
}
res.AddErrors(invalidParameterDefinitionAsSchemaMsg(path, in, operation))
} else if (pr.In == swaggerBody && pr.Schema == nil) ||
(pr.In != swaggerBody && pr.SimpleSchema == simpleZero) { // Safeguard
case (pr.In == swaggerBody && pr.Schema == nil) || (pr.In != swaggerBody && pr.SimpleSchema == simpleZero):
// Other unexpected mishaps
res.AddErrors(invalidParameterDefinitionMsg(path, in, operation))
}
@@ -254,8 +313,8 @@ func (r *responseHelper) responseMsgVariants(
responseType string,
responseCode int) (responseName, responseCodeAsStr string) {
// Path variants for messages
if responseType == "default" {
responseCodeAsStr = "default"
if responseType == jsonDefault {
responseCodeAsStr = jsonDefault
responseName = "default response"
} else {
responseCodeAsStr = strconv.Itoa(responseCode)

View File

@@ -51,40 +51,54 @@ func (o *objectValidator) Applies(source interface{}, kind reflect.Kind) bool {
return r
}
func (o *objectValidator) isPropertyName() bool {
func (o *objectValidator) isProperties() bool {
p := strings.Split(o.Path, ".")
return p[len(p)-1] == "properties" && p[len(p)-2] != "properties"
return len(p) > 1 && p[len(p)-1] == jsonProperties && p[len(p)-2] != jsonProperties
}
func (o *objectValidator) isDefault() bool {
p := strings.Split(o.Path, ".")
return len(p) > 1 && p[len(p)-1] == jsonDefault && p[len(p)-2] != jsonDefault
}
func (o *objectValidator) isExample() bool {
p := strings.Split(o.Path, ".")
return len(p) > 1 && (p[len(p)-1] == swaggerExample || p[len(p)-1] == swaggerExamples) && p[len(p)-2] != swaggerExample
}
func (o *objectValidator) checkArrayMustHaveItems(res *Result, val map[string]interface{}) {
if t, typeFound := val["type"]; typeFound {
if tpe, ok := t.(string); ok && tpe == "array" {
if _, itemsKeyFound := val["items"]; !itemsKeyFound {
res.AddErrors(errors.Required("items", o.Path))
// for swagger 2.0 schemas, there is an additional constraint to have array items defined explicitly.
// with pure jsonschema draft 4, one may have arrays with undefined items (i.e. any type).
if t, typeFound := val[jsonType]; typeFound {
if tpe, ok := t.(string); ok && tpe == arrayType {
if _, itemsKeyFound := val[jsonItems]; !itemsKeyFound {
res.AddErrors(errors.Required(jsonItems, o.Path))
}
}
}
}
func (o *objectValidator) checkItemsMustBeTypeArray(res *Result, val map[string]interface{}) {
if !o.isPropertyName() {
if _, itemsKeyFound := val["items"]; itemsKeyFound {
t, typeFound := val["type"]
if !o.isProperties() && !o.isDefault() && !o.isExample() {
if _, itemsKeyFound := val[jsonItems]; itemsKeyFound {
t, typeFound := val[jsonType]
if typeFound {
if tpe, ok := t.(string); !ok || tpe != "array" {
res.AddErrors(errors.InvalidType(o.Path, o.In, "array", nil))
if tpe, ok := t.(string); !ok || tpe != arrayType {
res.AddErrors(errors.InvalidType(o.Path, o.In, arrayType, nil))
}
} else {
// there is no type
res.AddErrors(errors.Required("type", o.Path))
res.AddErrors(errors.Required(jsonType, o.Path))
}
}
}
}
func (o *objectValidator) precheck(res *Result, val map[string]interface{}) {
o.checkArrayMustHaveItems(res, val)
if !o.Options.DisableObjectArrayTypeCheck {
if o.Options.EnableArrayMustHaveItemsCheck {
o.checkArrayMustHaveItems(res, val)
}
if o.Options.EnableObjectArrayTypeCheck {
o.checkItemsMustBeTypeArray(res, val)
}
}
@@ -134,21 +148,18 @@ func (o *objectValidator) Validate(data interface{}) *Result {
// NOTE: prefix your messages here by "IMPORTANT!" so there are not filtered
// by higher level callers (the IMPORTANT! tag will be eventually
// removed).
switch k {
// $ref is forbidden in header
case "headers":
if val[k] != nil {
if headers, mapOk := val[k].(map[string]interface{}); mapOk {
for headerKey, headerBody := range headers {
if headerBody != nil {
if headerSchema, mapOfMapOk := headerBody.(map[string]interface{}); mapOfMapOk {
if _, found := headerSchema["$ref"]; found {
var msg string
if refString, stringOk := headerSchema["$ref"].(string); stringOk {
msg = strings.Join([]string{", one may not use $ref=\":", refString, "\""}, "")
}
res.AddErrors(refNotAllowedInHeaderMsg(o.Path, headerKey, msg))
if k == "headers" && val[k] != nil {
// $ref is forbidden in header
if headers, mapOk := val[k].(map[string]interface{}); mapOk {
for headerKey, headerBody := range headers {
if headerBody != nil {
if headerSchema, mapOfMapOk := headerBody.(map[string]interface{}); mapOfMapOk {
if _, found := headerSchema["$ref"]; found {
var msg string
if refString, stringOk := headerSchema["$ref"].(string); stringOk {
msg = strings.Join([]string{", one may not use $ref=\":", refString, "\""}, "")
}
res.AddErrors(refNotAllowedInHeaderMsg(o.Path, headerKey, msg))
}
}
}

View File

@@ -132,6 +132,7 @@ func (r *Result) RootObjectSchemata() []*spec.Schema {
}
// FieldSchemata returns the schemata which apply to fields in objects.
// nolint: dupl
func (r *Result) FieldSchemata() map[FieldKey][]*spec.Schema {
if r.cachedFieldSchemta != nil {
return r.cachedFieldSchemta
@@ -151,6 +152,7 @@ func (r *Result) FieldSchemata() map[FieldKey][]*spec.Schema {
}
// ItemSchemata returns the schemata which apply to items in slices.
// nolint: dupl
func (r *Result) ItemSchemata() map[ItemKey][]*spec.Schema {
if r.cachedItemSchemata != nil {
return r.cachedItemSchemata
@@ -175,6 +177,7 @@ func (r *Result) resetCaches() {
}
// mergeForField merges other into r, assigning other's root schemata to the given Object and field name.
// nolint: unparam
func (r *Result) mergeForField(obj map[string]interface{}, field string, other *Result) *Result {
if other == nil {
return r
@@ -196,6 +199,7 @@ func (r *Result) mergeForField(obj map[string]interface{}, field string, other *
}
// mergeForSlice merges other into r, assigning other's root schemata to the given slice and index.
// nolint: unparam
func (r *Result) mergeForSlice(slice reflect.Value, i int, other *Result) *Result {
if other == nil {
return r
@@ -231,6 +235,7 @@ func (r *Result) addPropertySchemata(obj map[string]interface{}, fld string, sch
r.fieldSchemata = append(r.fieldSchemata, fieldSchemata{obj: obj, field: fld, schemata: schemata{one: schema}})
}
/*
// addSliceSchemata adds the given schemata for the slice and index.
// The slice schemata might be reused. I.e. do not modify it after being added to a result.
func (r *Result) addSliceSchemata(slice reflect.Value, i int, schema *spec.Schema) {
@@ -239,6 +244,7 @@ func (r *Result) addSliceSchemata(slice reflect.Value, i int, schema *spec.Schem
}
r.itemSchemata = append(r.itemSchemata, itemSchemata{slice: slice, index: i, schemata: schemata{one: schema}})
}
*/
// mergeWithoutRootSchemata merges other into r, ignoring the rootObject schemata.
func (r *Result) mergeWithoutRootSchemata(other *Result) {
@@ -251,9 +257,7 @@ func (r *Result) mergeWithoutRootSchemata(other *Result) {
if r.fieldSchemata == nil {
r.fieldSchemata = other.fieldSchemata
} else {
for _, x := range other.fieldSchemata {
r.fieldSchemata = append(r.fieldSchemata, x)
}
r.fieldSchemata = append(r.fieldSchemata, other.fieldSchemata...)
}
}
@@ -261,9 +265,7 @@ func (r *Result) mergeWithoutRootSchemata(other *Result) {
if r.itemSchemata == nil {
r.itemSchemata = other.itemSchemata
} else {
for _, x := range other.itemSchemata {
r.itemSchemata = append(r.itemSchemata, x)
}
r.itemSchemata = append(r.itemSchemata, other.itemSchemata...)
}
}
}

View File

@@ -27,8 +27,8 @@ import (
var (
specSchemaType = reflect.TypeOf(&spec.Schema{})
specParameterType = reflect.TypeOf(&spec.Parameter{})
specItemsType = reflect.TypeOf(&spec.Items{})
specHeaderType = reflect.TypeOf(&spec.Header{})
//specItemsType = reflect.TypeOf(&spec.Items{})
)
// SchemaValidator validates data against a JSON schema
@@ -39,14 +39,14 @@ type SchemaValidator struct {
validators []valueValidator
Root interface{}
KnownFormats strfmt.Registry
Options *SchemaValidatorOptions
Options SchemaValidatorOptions
}
// 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.
func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry) error {
res := NewSchemaValidator(schema, nil, "", formats).Validate(data)
func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry, options ...Option) error {
res := NewSchemaValidator(schema, nil, "", formats, options...).Validate(data)
if res.HasErrors() {
return errors.CompositeValidationError(res.Errors...)
}
@@ -72,9 +72,15 @@ func NewSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string
panic(msg)
}
}
s := SchemaValidator{Path: root, in: "body", Schema: schema, Root: rootSchema, KnownFormats: formats, Options: &SchemaValidatorOptions{}}
s := SchemaValidator{
Path: root,
in: "body",
Schema: schema,
Root: rootSchema,
KnownFormats: formats,
Options: SchemaValidatorOptions{}}
for _, o := range options {
o(s.Options)
o(&s.Options)
}
s.validators = []valueValidator{
s.typeValidator(),
@@ -134,9 +140,9 @@ func (s *SchemaValidator) Validate(data interface{}) *Result {
// TODO: this part should be handed over to type validator
// Handle special case of json.Number data (number marshalled as string)
isnumber := s.Schema.Type.Contains("number") || s.Schema.Type.Contains("integer")
isnumber := s.Schema.Type.Contains(numberType) || s.Schema.Type.Contains(integerType)
if num, ok := data.(json.Number); ok && isnumber {
if s.Schema.Type.Contains("integer") { // avoid lossy conversion
if s.Schema.Type.Contains(integerType) { // avoid lossy conversion
in, erri := num.Int64()
if erri != nil {
result.AddErrors(invalidTypeConversionMsg(s.Path, erri))
@@ -196,6 +202,7 @@ func (s *SchemaValidator) sliceValidator() valueValidator {
Items: s.Schema.Items,
Root: s.Root,
KnownFormats: s.KnownFormats,
Options: s.Options,
}
}
@@ -248,6 +255,6 @@ func (s *SchemaValidator) objectValidator() valueValidator {
PatternProperties: s.Schema.PatternProperties,
Root: s.Root,
KnownFormats: s.KnownFormats,
Options: *s.Options,
Options: s.Options,
}
}

View File

@@ -14,20 +14,41 @@
package validate
// SchemaValidatorOptions defines optional rules for schema validation
type SchemaValidatorOptions struct {
DisableObjectArrayTypeCheck bool
EnableObjectArrayTypeCheck bool
EnableArrayMustHaveItemsCheck bool
}
// Option sets optional rules for schema validation
type Option func(*SchemaValidatorOptions)
func DisableObjectArrayTypeCheck(disable bool) Option {
// EnableObjectArrayTypeCheck activates the swagger rule: an items must be in type: array
func EnableObjectArrayTypeCheck(enable bool) Option {
return func(svo *SchemaValidatorOptions) {
svo.DisableObjectArrayTypeCheck = disable
svo.EnableObjectArrayTypeCheck = enable
}
}
func (svo SchemaValidatorOptions) Options() []Option {
return []Option{
DisableObjectArrayTypeCheck(svo.DisableObjectArrayTypeCheck),
// EnableArrayMustHaveItemsCheck activates the swagger rule: an array must have items defined
func EnableArrayMustHaveItemsCheck(enable bool) Option {
return func(svo *SchemaValidatorOptions) {
svo.EnableArrayMustHaveItemsCheck = enable
}
}
// SwaggerSchema activates swagger schema validation rules
func SwaggerSchema(enable bool) Option {
return func(svo *SchemaValidatorOptions) {
svo.EnableObjectArrayTypeCheck = enable
svo.EnableArrayMustHaveItemsCheck = enable
}
}
// Options returns current options
func (svo SchemaValidatorOptions) Options() []Option {
return []Option{
EnableObjectArrayTypeCheck(svo.EnableObjectArrayTypeCheck),
EnableArrayMustHaveItemsCheck(svo.EnableArrayMustHaveItemsCheck),
}
}

View File

@@ -32,6 +32,7 @@ type schemaSliceValidator struct {
Items *spec.SchemaOrArray
Root interface{}
KnownFormats strfmt.Registry
Options SchemaValidatorOptions
}
func (s *schemaSliceValidator) SetPath(path string) {
@@ -53,7 +54,7 @@ func (s *schemaSliceValidator) Validate(data interface{}) *Result {
size := val.Len()
if s.Items != nil && s.Items.Schema != nil {
validator := NewSchemaValidator(s.Items.Schema, s.Root, s.Path, s.KnownFormats)
validator := NewSchemaValidator(s.Items.Schema, s.Root, s.Path, s.KnownFormats, s.Options.Options()...)
for i := 0; i < size; i++ {
validator.SetPath(fmt.Sprintf("%s.%d", s.Path, i))
value := val.Index(i)
@@ -65,11 +66,11 @@ func (s *schemaSliceValidator) Validate(data interface{}) *Result {
if s.Items != nil && len(s.Items.Schemas) > 0 {
itemsSize = len(s.Items.Schemas)
for i := 0; i < itemsSize; i++ {
validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats)
validator := NewSchemaValidator(&s.Items.Schemas[i], s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats, s.Options.Options()...)
if val.Len() <= i {
break
}
result.mergeForSlice(val, int(i), validator.Validate(val.Index(i).Interface()))
result.mergeForSlice(val, i, validator.Validate(val.Index(i).Interface()))
}
}
if s.AdditionalItems != nil && itemsSize < size {
@@ -78,8 +79,8 @@ func (s *schemaSliceValidator) Validate(data interface{}) *Result {
}
if s.AdditionalItems.Schema != nil {
for i := itemsSize; i < size-itemsSize+1; i++ {
validator := NewSchemaValidator(s.AdditionalItems.Schema, s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats)
result.mergeForSlice(val, int(i), validator.Validate(val.Index(int(i)).Interface()))
validator := NewSchemaValidator(s.AdditionalItems.Schema, s.Root, fmt.Sprintf("%s.%d", s.Path, i), s.KnownFormats, s.Options.Options()...)
result.mergeForSlice(val, i, validator.Validate(val.Index(i).Interface()))
}
}
}

View File

@@ -71,25 +71,22 @@ func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidat
}
// Validate validates the swagger spec
func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Result) {
func (s *SpecValidator) Validate(data interface{}) (*Result, *Result) {
var sd *loads.Document
errs = new(Result)
errs, warnings := new(Result), new(Result)
switch v := data.(type) {
case *loads.Document:
if v, ok := data.(*loads.Document); ok {
sd = v
}
if sd == nil {
errs.AddErrors(invalidDocumentMsg())
return
return errs, warnings // no point in continuing
}
s.spec = sd
s.analyzer = analysis.New(sd.Spec())
warnings = new(Result)
// Swagger schema validator
schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats)
schv := NewSchemaValidator(s.schema, nil, "", s.KnownFormats, SwaggerSchema(true))
var obj interface{}
// Raw spec unmarshalling errors
@@ -109,13 +106,13 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
errs.Merge(schv.Validate(obj)) // error -
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
return // no point in continuing
return errs, warnings // no point in continuing
}
errs.Merge(s.validateReferencesValid()) // error -
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
return // no point in continuing
return errs, warnings // no point in continuing
}
errs.Merge(s.validateDuplicateOperationIDs())
@@ -129,7 +126,7 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
// There may be a point in continuing to try and determine more accurate errors
if !s.Options.ContinueOnErrors && errs.HasErrors() {
return // no point in continuing
return errs, warnings // no point in continuing
}
// Values provided as default MUST validate their schema
@@ -147,7 +144,7 @@ func (s *SpecValidator) Validate(data interface{}) (errs *Result, warnings *Resu
//errs.Merge(s.validateRefNoSibling()) // warning only
errs.Merge(s.validateReferenced()) // warning only
return
return errs, warnings
}
func (s *SpecValidator) validateNonEmptyPathParamNames() *Result {
@@ -336,14 +333,14 @@ func (s *SpecValidator) validateItems() *Result {
for path, op := range pi {
for _, param := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
if param.TypeName() == "array" && param.ItemsTypeName() == "" {
if param.TypeName() == arrayType && param.ItemsTypeName() == "" {
res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID))
continue
}
if param.In != "body" {
if param.In != swaggerBody {
if param.Items != nil {
items := param.Items
for items.TypeName() == "array" {
for items.TypeName() == arrayType {
if items.ItemsTypeName() == "" {
res.AddErrors(arrayInParamRequiresItemsMsg(param.Name, op.ID))
break
@@ -374,7 +371,7 @@ func (s *SpecValidator) validateItems() *Result {
for _, resp := range responses {
// Response headers with array
for hn, hv := range resp.Headers {
if hv.TypeName() == "array" && hv.ItemsTypeName() == "" {
if hv.TypeName() == arrayType && hv.ItemsTypeName() == "" {
res.AddErrors(arrayInHeaderRequiresItemsMsg(hn, op.ID))
}
}
@@ -390,7 +387,7 @@ func (s *SpecValidator) validateItems() *Result {
// Verifies constraints on array type
func (s *SpecValidator) validateSchemaItems(schema spec.Schema, prefix, opID string) *Result {
res := new(Result)
if !schema.Type.Contains("array") {
if !schema.Type.Contains(arrayType) {
return res
}
@@ -451,6 +448,7 @@ func (s *SpecValidator) validateReferenced() *Result {
return &res
}
// nolint: dupl
func (s *SpecValidator) validateReferencedParameters() *Result {
// Each referenceable definition should have references.
params := s.spec.Spec().Parameters
@@ -463,9 +461,7 @@ func (s *SpecValidator) validateReferencedParameters() *Result {
expected["#/parameters/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllParameterReferences() {
if _, ok := expected[k]; ok {
delete(expected, k)
}
delete(expected, k)
}
if len(expected) == 0 {
@@ -478,6 +474,7 @@ func (s *SpecValidator) validateReferencedParameters() *Result {
return result
}
// nolint: dupl
func (s *SpecValidator) validateReferencedResponses() *Result {
// Each referenceable definition should have references.
responses := s.spec.Spec().Responses
@@ -490,9 +487,7 @@ func (s *SpecValidator) validateReferencedResponses() *Result {
expected["#/responses/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllResponseReferences() {
if _, ok := expected[k]; ok {
delete(expected, k)
}
delete(expected, k)
}
if len(expected) == 0 {
@@ -505,6 +500,7 @@ func (s *SpecValidator) validateReferencedResponses() *Result {
return result
}
// nolint: dupl
func (s *SpecValidator) validateReferencedDefinitions() *Result {
// Each referenceable definition must have references.
defs := s.spec.Spec().Definitions
@@ -517,9 +513,7 @@ func (s *SpecValidator) validateReferencedDefinitions() *Result {
expected["#/definitions/"+jsonpointer.Escape(k)] = struct{}{}
}
for _, k := range s.analyzer.AllDefinitionReferences() {
if _, ok := expected[k]; ok {
delete(expected, k)
}
delete(expected, k)
}
if len(expected) == 0 {
@@ -624,98 +618,114 @@ func (s *SpecValidator) validateParameters() *Result {
rexGarbledPathSegment := mustCompileRegexp(`.*[{}\s]+.*`)
for method, pi := range s.analyzer.Operations() {
methodPaths := make(map[string]map[string]string)
if pi != nil { // Safeguard
for path, op := range pi {
pathToAdd := pathHelp.stripParametersInPath(path)
for path, op := range pi {
pathToAdd := pathHelp.stripParametersInPath(path)
// Warn on garbled path afer param stripping
if rexGarbledPathSegment.MatchString(pathToAdd) {
res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
}
// Check uniqueness of stripped paths
if _, found := methodPaths[method][pathToAdd]; found {
// Sort names for stable, testable output
if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
} else {
res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
}
} else {
if _, found := methodPaths[method]; !found {
methodPaths[method] = map[string]string{}
}
methodPaths[method][pathToAdd] = path //Original non stripped path
}
var bodyParams []string
var paramNames []string
var hasForm, hasBody bool
// Check parameters names uniqueness for operation
// TODO: should be done after param expansion
res.Merge(s.checkUniqueParams(path, method, op))
for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
// Validate pattern regexp for parameters with a Pattern property
if _, err := compileRegexp(pr.Pattern); err != nil {
res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern))
}
// There must be at most one parameter in body: list them all
if pr.In == "body" {
bodyParams = append(bodyParams, fmt.Sprintf("%q", pr.Name))
hasBody = true
}
if pr.In == "path" {
paramNames = append(paramNames, pr.Name)
// Path declared in path must have the required: true property
if !pr.Required {
res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name))
}
}
if pr.In == "formData" {
hasForm = true
}
}
// In:formData and In:body are mutually exclusive
if hasBody && hasForm {
res.AddErrors(bothFormDataAndBodyMsg(op.ID))
}
// There must be at most one body param
// Accurately report situations when more than 1 body param is declared (possibly unnamed)
if len(bodyParams) > 1 {
sort.Strings(bodyParams)
res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams))
}
// Check uniqueness of parameters in path
paramsInPath := pathHelp.extractPathParams(path)
for i, p := range paramsInPath {
for j, q := range paramsInPath {
if p == q && i > j {
res.AddErrors(pathParamNotUniqueMsg(path, p, q))
break
}
}
}
// Warns about possible malformed params in path
rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`)
for _, p := range paramsInPath {
if rexGarbledParam.MatchString(p) {
res.AddWarnings(pathParamGarbledMsg(path, p))
}
}
// Match params from path vs params from params section
res.Merge(s.validatePathParamPresence(path, paramsInPath, paramNames))
// Warn on garbled path afer param stripping
if rexGarbledPathSegment.MatchString(pathToAdd) {
res.AddWarnings(pathStrippedParamGarbledMsg(pathToAdd))
}
// Check uniqueness of stripped paths
if _, found := methodPaths[method][pathToAdd]; found {
// Sort names for stable, testable output
if strings.Compare(path, methodPaths[method][pathToAdd]) < 0 {
res.AddErrors(pathOverlapMsg(path, methodPaths[method][pathToAdd]))
} else {
res.AddErrors(pathOverlapMsg(methodPaths[method][pathToAdd], path))
}
} else {
if _, found := methodPaths[method]; !found {
methodPaths[method] = map[string]string{}
}
methodPaths[method][pathToAdd] = path //Original non stripped path
}
var bodyParams []string
var paramNames []string
var hasForm, hasBody bool
// Check parameters names uniqueness for operation
// TODO: should be done after param expansion
res.Merge(s.checkUniqueParams(path, method, op))
for _, pr := range paramHelp.safeExpandedParamsFor(path, method, op.ID, res, s) {
// Validate pattern regexp for parameters with a Pattern property
if _, err := compileRegexp(pr.Pattern); err != nil {
res.AddErrors(invalidPatternInParamMsg(op.ID, pr.Name, pr.Pattern))
}
// There must be at most one parameter in body: list them all
if pr.In == swaggerBody {
bodyParams = append(bodyParams, fmt.Sprintf("%q", pr.Name))
hasBody = true
}
if pr.In == "path" {
paramNames = append(paramNames, pr.Name)
// Path declared in path must have the required: true property
if !pr.Required {
res.AddErrors(pathParamRequiredMsg(op.ID, pr.Name))
}
}
if pr.In == "formData" {
hasForm = true
}
if !(pr.Type == numberType || pr.Type == integerType) &&
(pr.Maximum != nil || pr.Minimum != nil || pr.MultipleOf != nil) {
// A non-numeric parameter has validation keywords for numeric instances (number and integer)
res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
}
if !(pr.Type == stringType) &&
// A non-string parameter has validation keywords for strings
(pr.MaxLength != nil || pr.MinLength != nil || pr.Pattern != "") {
res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
}
if !(pr.Type == arrayType) &&
// A non-array parameter has validation keywords for arrays
(pr.MaxItems != nil || pr.MinItems != nil || pr.UniqueItems) {
res.AddWarnings(parameterValidationTypeMismatchMsg(pr.Name, path, pr.Type))
}
}
// In:formData and In:body are mutually exclusive
if hasBody && hasForm {
res.AddErrors(bothFormDataAndBodyMsg(op.ID))
}
// There must be at most one body param
// Accurately report situations when more than 1 body param is declared (possibly unnamed)
if len(bodyParams) > 1 {
sort.Strings(bodyParams)
res.AddErrors(multipleBodyParamMsg(op.ID, bodyParams))
}
// Check uniqueness of parameters in path
paramsInPath := pathHelp.extractPathParams(path)
for i, p := range paramsInPath {
for j, q := range paramsInPath {
if p == q && i > j {
res.AddErrors(pathParamNotUniqueMsg(path, p, q))
break
}
}
}
// Warns about possible malformed params in path
rexGarbledParam := mustCompileRegexp(`{.*[{}\s]+.*}`)
for _, p := range paramsInPath {
if rexGarbledParam.MatchString(p) {
res.AddWarnings(pathParamGarbledMsg(path, p))
}
}
// Match params from path vs params from params section
res.Merge(s.validatePathParamPresence(path, paramsInPath, paramNames))
}
}
return res

View File

@@ -163,6 +163,9 @@ const (
// PathParamGarbledWarning ...
PathParamGarbledWarning = "in path %q, param %q contains {,} or white space. Albeit not stricly illegal, this is probably no what you want"
// ParamValidationTypeMismatch indicates that parameter has validation which does not match its type
ParamValidationTypeMismatch = "validation keywords of parameter %q in path %q don't match its type %s"
// PathStrippedParamGarbledWarning ...
PathStrippedParamGarbledWarning = "path stripped from path parameters %s contains {,} or white space. This is probably no what you want."
@@ -341,6 +344,9 @@ func invalidParameterDefinitionMsg(path, method, operationID string) errors.Erro
func invalidParameterDefinitionAsSchemaMsg(path, method, operationID string) errors.Error {
return errors.New(errors.CompositeErrorCode, InvalidParameterDefinitionAsSchemaError, path, method, operationID)
}
func parameterValidationTypeMismatchMsg(param, path, typ string) errors.Error {
return errors.New(errors.CompositeErrorCode, ParamValidationTypeMismatch, param, path, typ)
}
// disabled
//func invalidResponseDefinitionAsSchemaMsg(path, method string) errors.Error {

View File

@@ -39,53 +39,53 @@ func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) {
// TODO: this switch really is some sort of reverse lookup for formats. It should be provided by strfmt.
switch data.(type) {
case []byte, strfmt.Base64, *strfmt.Base64:
return "string", "byte"
return stringType, stringFormatByte
case strfmt.CreditCard, *strfmt.CreditCard:
return "string", "creditcard"
return stringType, stringFormatCreditCard
case strfmt.Date, *strfmt.Date:
return "string", "date"
return stringType, stringFormatDate
case strfmt.DateTime, *strfmt.DateTime:
return "string", "date-time"
return stringType, stringFormatDateTime
case strfmt.Duration, *strfmt.Duration:
return "string", "duration"
return stringType, stringFormatDuration
case runtime.File, *runtime.File:
return "file", ""
return fileType, ""
case strfmt.Email, *strfmt.Email:
return "string", "email"
return stringType, stringFormatEmail
case strfmt.HexColor, *strfmt.HexColor:
return "string", "hexcolor"
return stringType, stringFormatHexColor
case strfmt.Hostname, *strfmt.Hostname:
return "string", "hostname"
return stringType, stringFormatHostname
case strfmt.IPv4, *strfmt.IPv4:
return "string", "ipv4"
return stringType, stringFormatIPv4
case strfmt.IPv6, *strfmt.IPv6:
return "string", "ipv6"
return stringType, stringFormatIPv6
case strfmt.ISBN, *strfmt.ISBN:
return "string", "isbn"
return stringType, stringFormatISBN
case strfmt.ISBN10, *strfmt.ISBN10:
return "string", "isbn10"
return stringType, stringFormatISBN10
case strfmt.ISBN13, *strfmt.ISBN13:
return "string", "isbn13"
return stringType, stringFormatISBN13
case strfmt.MAC, *strfmt.MAC:
return "string", "mac"
return stringType, stringFormatMAC
case strfmt.ObjectId, *strfmt.ObjectId:
return "string", "bsonobjectid"
return stringType, stringFormatBSONObjectID
case strfmt.Password, *strfmt.Password:
return "string", "password"
return stringType, stringFormatPassword
case strfmt.RGBColor, *strfmt.RGBColor:
return "string", "rgbcolor"
return stringType, stringFormatRGBColor
case strfmt.SSN, *strfmt.SSN:
return "string", "ssn"
return stringType, stringFormatSSN
case strfmt.URI, *strfmt.URI:
return "string", "uri"
return stringType, stringFormatURI
case strfmt.UUID, *strfmt.UUID:
return "string", "uuid"
return stringType, stringFormatUUID
case strfmt.UUID3, *strfmt.UUID3:
return "string", "uuid3"
return stringType, stringFormatUUID3
case strfmt.UUID4, *strfmt.UUID4:
return "string", "uuid4"
return stringType, stringFormatUUID4
case strfmt.UUID5, *strfmt.UUID5:
return "string", "uuid5"
return stringType, stringFormatUUID5
// TODO: missing binary (io.ReadCloser)
// TODO: missing json.Number
default:
@@ -93,25 +93,25 @@ func (t *typeValidator) schemaInfoForType(data interface{}) (string, string) {
tpe := val.Type()
switch tpe.Kind() {
case reflect.Bool:
return "boolean", ""
return booleanType, ""
case reflect.String:
return "string", ""
return stringType, ""
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint8, reflect.Uint16, reflect.Uint32:
// NOTE: that is the spec. With go-openapi, is that not uint32 for unsigned integers?
return "integer", "int32"
return integerType, integerFormatInt32
case reflect.Int, reflect.Int64, reflect.Uint, reflect.Uint64:
return "integer", "int64"
return integerType, integerFormatInt64
case reflect.Float32:
// NOTE: is that not "float"?
return "number", "float32"
// NOTE: is that not numberFormatFloat?
return numberType, numberFormatFloat32
case reflect.Float64:
// NOTE: is that not "double"?
return "number", "float64"
return numberType, numberFormatFloat64
// NOTE: go arrays (reflect.Array) are not supported (fixed length)
case reflect.Slice:
return "array", ""
return arrayType, ""
case reflect.Map, reflect.Struct:
return "object", ""
return objectType, ""
case reflect.Interface:
// What to do here?
panic("dunno what to do here")
@@ -139,8 +139,8 @@ func (t *typeValidator) Validate(data interface{}) *Result {
result.Inc()
if data == nil || reflect.DeepEqual(reflect.Zero(reflect.TypeOf(data)), reflect.ValueOf(data)) {
// nil or zero value for the passed structure require Type: null
if len(t.Type) > 0 && !t.Type.Contains("null") && !t.Nullable { // TODO: if a property is not required it also passes this
return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), "null"))
if len(t.Type) > 0 && !t.Type.Contains(nullType) && !t.Nullable { // TODO: if a property is not required it also passes this
return errorHelp.sErr(errors.InvalidType(t.Path, t.In, strings.Join(t.Type, ","), nullType))
}
return result
}
@@ -157,17 +157,17 @@ func (t *typeValidator) Validate(data interface{}) *Result {
// check numerical types
// TODO: check unsigned ints
// TODO: check json.Number (see schema.go)
isLowerInt := t.Format == "int64" && format == "int32"
isLowerFloat := t.Format == "float64" && format == "float32"
isFloatInt := schType == "number" && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains("integer")
isIntFloat := schType == "integer" && t.Type.Contains("number")
isLowerInt := t.Format == integerFormatInt64 && format == integerFormatInt32
isLowerFloat := t.Format == numberFormatFloat64 && format == numberFormatFloat32
isFloatInt := schType == numberType && swag.IsFloat64AJSONInteger(val.Float()) && t.Type.Contains(integerType)
isIntFloat := schType == integerType && t.Type.Contains(numberType)
if kind != reflect.String && kind != reflect.Slice && t.Format != "" && !(t.Type.Contains(schType) || format == t.Format || isFloatInt || isIntFloat || isLowerInt || isLowerFloat) {
// TODO: test case
return errorHelp.sErr(errors.InvalidType(t.Path, t.In, t.Format, format))
}
if !(t.Type.Contains("number") || t.Type.Contains("integer")) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) {
if !(t.Type.Contains(numberType) || t.Type.Contains(integerType)) && t.Format != "" && (kind == reflect.String || kind == reflect.Slice) {
return result
}

View File

@@ -452,6 +452,7 @@ func (s *basicSliceValidator) Validate(data interface{}) *Result {
return nil
}
/* unused
func (s *basicSliceValidator) hasDuplicates(value reflect.Value, size int) bool {
dict := make(map[interface{}]struct{})
for i := 0; i < size; i++ {
@@ -463,6 +464,7 @@ func (s *basicSliceValidator) hasDuplicates(value reflect.Value, size int) bool
}
return false
}
*/
type numberValidator struct {
Path string
@@ -530,6 +532,7 @@ func (n *numberValidator) Validate(val interface{}) *Result {
// Is the provided value within the range of the specified numeric type and format?
res.AddErrors(IsValueValidAgainstRange(val, n.Type, n.Format, "Checked", n.Path))
// nolint: dupl
if n.MultipleOf != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMultiple.AddErrors(IsValueValidAgainstRange(*n.MultipleOf, n.Type, n.Format, "MultipleOf", n.Path))
@@ -546,6 +549,7 @@ func (n *numberValidator) Validate(val interface{}) *Result {
}
}
// nolint: dupl
if n.Maximum != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMaximum.AddErrors(IsValueValidAgainstRange(*n.Maximum, n.Type, n.Format, "Maximum boundary", n.Path))
@@ -562,6 +566,7 @@ func (n *numberValidator) Validate(val interface{}) *Result {
}
}
// nolint: dupl
if n.Minimum != nil {
// Is the constraint specifier within the range of the specific numeric type and format?
resMinimum.AddErrors(IsValueValidAgainstRange(*n.Minimum, n.Type, n.Format, "Minimum boundary", n.Path))
@@ -611,7 +616,7 @@ func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool {
func (s *stringValidator) Validate(val interface{}) *Result {
data, ok := val.(string)
if !ok {
return errorHelp.sErr(errors.InvalidType(s.Path, s.In, "string", val))
return errorHelp.sErr(errors.InvalidType(s.Path, s.In, stringType, val))
}
if s.Required && !s.AllowEmptyValue && (s.Default == nil || s.Default == "") {

View File

@@ -361,26 +361,26 @@ func IsValueValidAgainstRange(val interface{}, typeName, format, prefix, path st
var errVal error
switch typeName {
case "integer":
case integerType:
switch format {
case "int32":
case integerFormatInt32:
_, errVal = swag.ConvertInt32(stringRep)
case "uint32":
case integerFormatUInt32:
_, errVal = swag.ConvertUint32(stringRep)
case "uint64":
case integerFormatUInt64:
_, errVal = swag.ConvertUint64(stringRep)
case "int64":
case integerFormatInt64:
fallthrough
default:
_, errVal = swag.ConvertInt64(stringRep)
}
case "number":
case numberType:
fallthrough
default:
switch format {
case "float", "float32":
case numberFormatFloat, numberFormatFloat32:
_, errVal = swag.ConvertFloat32(stringRep)
case "double", "float64":
case numberFormatDouble, numberFormatFloat64:
fallthrough
default:
// No check can be performed here since