Skip to content

Commit 94e900b

Browse files
committed
defaulting: implement orthogonally to validation
1 parent c7c5d5c commit 94e900b

File tree

7 files changed

+331
-58
lines changed

7 files changed

+331
-58
lines changed

helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ func (h *paramHelper) safeExpandedParamsFor(path, method, operationID string, re
159159
resolvedParams = append(resolvedParams, *resolvedParam)
160160
}
161161
}
162-
// remove params with invalid expansion from slice
162+
// remove params with invalid expansion from Slice
163163
operation.Parameters = resolvedParams
164164

165165
for _, ppr := range s.analyzer.SafeParamsFor(method, path,

object_validator.go

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func (o *objectValidator) Validate(data interface{}) *Result {
102102

103103
o.precheck(res, val)
104104

105+
// check validity of field names
105106
if o.AdditionalProperties != nil && !o.AdditionalProperties.Allows {
106107
// Case: additionalProperties: false
107108
for k := range val {
@@ -175,7 +176,8 @@ func (o *objectValidator) Validate(data interface{}) *Result {
175176
// Cases: properties which are not regular properties and have not been matched by the PatternProperties validator
176177
if o.AdditionalProperties != nil && o.AdditionalProperties.Schema != nil {
177178
// AdditionalProperties as Schema
178-
res.Merge(NewSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value))
179+
r := NewSchemaValidator(o.AdditionalProperties.Schema, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value)
180+
res.mergeForField(data.(map[string]interface{}), key, r)
179181
} else if regularProperty && !(matched || succeededOnce) {
180182
// TODO: this is dead code since regularProperty=false here
181183
res.AddErrors(errors.FailedAllPatternProperties(o.Path, o.In, key))
@@ -189,7 +191,8 @@ func (o *objectValidator) Validate(data interface{}) *Result {
189191

190192
// Property types:
191193
// - regular Property
192-
for pName, pSchema := range o.Properties {
194+
for pName := range o.Properties {
195+
pSchema := o.Properties[pName] // one instance per iteration
193196
rName := pName
194197
if o.Path != "" {
195198
rName = o.Path + "." + pName
@@ -198,17 +201,12 @@ func (o *objectValidator) Validate(data interface{}) *Result {
198201
// Recursively validates each property against its schema
199202
if v, ok := val[pName]; ok {
200203
r := NewSchemaValidator(&pSchema, o.Root, rName, o.KnownFormats).Validate(v)
201-
res.Merge(r)
204+
res.mergeForField(data.(map[string]interface{}), pName, r)
202205
} else if pSchema.Default != nil {
203206
// If a default value is defined, creates the property from defaults
204207
// NOTE: JSON schema does not enforce default values to be valid against schema. Swagger does.
205208
createdFromDefaults[pName] = true
206-
pName := pName // shadow
207-
// TODO: should validate the default first and ignore the value if invalid
208-
def := pSchema.Default
209-
res.Defaulters = append(res.Defaulters, DefaulterFunc(func() {
210-
val[pName] = def
211-
}))
209+
res.addPropertySchemata(data.(map[string]interface{}), pName, &pSchema)
212210
}
213211
}
214212

@@ -230,7 +228,8 @@ func (o *objectValidator) Validate(data interface{}) *Result {
230228
if !regularProperty && (matched /*|| succeededOnce*/) {
231229
for _, pName := range patterns {
232230
if v, ok := o.PatternProperties[pName]; ok {
233-
res.Merge(NewSchemaValidator(&v, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value))
231+
r := NewSchemaValidator(&v, o.Root, o.Path+"."+key, o.KnownFormats).Validate(value)
232+
res.mergeForField(data.(map[string]interface{}), key, r)
234233
}
235234
}
236235
}
Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2015 go-swagger maintainers
1+
// Copyright 2018 go-swagger maintainers
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -12,18 +12,22 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package validate
15+
package post
1616

17-
// Defaulter defines an interface to define values from default values
18-
// provided in a schema.
19-
type Defaulter interface {
20-
Apply()
21-
}
22-
23-
// DefaulterFunc is a function to be called to apply default values to an object.
24-
type DefaulterFunc func()
17+
import (
18+
"github.com/go-openapi/validate"
19+
)
2520

26-
// Apply runs the defaulter function, thus applying default values to an object.
27-
func (f DefaulterFunc) Apply() {
28-
f()
21+
// ApplyDefaults applies defaults to data.
22+
func ApplyDefaults(r *validate.Result) {
23+
fieldSchemata := r.FieldSchemata()
24+
for key, schemata := range fieldSchemata {
25+
LookForDefaultingScheme:
26+
for _, s := range schemata {
27+
if s.Default != nil {
28+
key.Object()[key.Field()] = s.Default
29+
break LookForDefaultingScheme
30+
}
31+
}
32+
}
2933
}

defaulter_test.go renamed to post/defaulter_test.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
package validate
15+
package post
1616

1717
import (
1818
"encoding/json"
@@ -25,22 +25,23 @@ import (
2525

2626
"github.com/go-openapi/spec"
2727
"github.com/go-openapi/strfmt"
28+
"github.com/go-openapi/validate"
2829
)
2930

30-
var defaulterFixturesPath = filepath.Join("fixtures", "defaulting")
31+
var defaulterFixturesPath = filepath.Join("..", "fixtures", "defaulting")
3132

3233
func TestDefaulter(t *testing.T) {
3334
schema, err := defaulterFixture()
3435
assert.NoError(t, err)
3536

36-
validator := NewSchemaValidator(schema, nil, "", strfmt.Default)
37+
validator := validate.NewSchemaValidator(schema, nil, "", strfmt.Default)
3738
x := defaulterFixtureInput()
3839
t.Logf("Before: %v", x)
3940

4041
r := validator.Validate(x)
4142
assert.False(t, r.HasErrors(), fmt.Sprintf("unexpected validation error: %v", r.AsError()))
4243

43-
r.ApplyDefaults()
44+
ApplyDefaults(r)
4445
t.Logf("After: %v", x)
4546
var expected interface{}
4647
err = json.Unmarshal([]byte(`{
@@ -60,26 +61,26 @@ func TestDefaulterSimple(t *testing.T) {
6061
schema := spec.Schema{
6162
SchemaProps: spec.SchemaProps{
6263
Properties: map[string]spec.Schema{
63-
"int": spec.Schema{
64+
"int": {
6465
SchemaProps: spec.SchemaProps{
6566
Default: float64(42),
6667
},
6768
},
68-
"str": spec.Schema{
69+
"str": {
6970
SchemaProps: spec.SchemaProps{
7071
Default: "Hello",
7172
},
7273
},
7374
},
7475
},
7576
}
76-
validator := NewSchemaValidator(&schema, nil, "", strfmt.Default)
77+
validator := validate.NewSchemaValidator(&schema, nil, "", strfmt.Default)
7778
x := map[string]interface{}{}
7879
t.Logf("Before: %v", x)
7980
r := validator.Validate(x)
8081
assert.False(t, r.HasErrors(), fmt.Sprintf("unexpected validation error: %v", r.AsError()))
8182

82-
r.ApplyDefaults()
83+
ApplyDefaults(r)
8384
t.Logf("After: %v", x)
8485
var expected interface{}
8586
err := json.Unmarshal([]byte(`{
@@ -92,16 +93,16 @@ func TestDefaulterSimple(t *testing.T) {
9293

9394
func BenchmarkDefaulting(b *testing.B) {
9495
b.ReportAllocs()
95-
96+
9697
schema, err := defaulterFixture()
9798
assert.NoError(b, err)
9899

99100
for n := 0; n < b.N; n++ {
100-
validator := NewSchemaValidator(schema, nil, "", strfmt.Default)
101+
validator := validate.NewSchemaValidator(schema, nil, "", strfmt.Default)
101102
x := defaulterFixtureInput()
102103
r := validator.Validate(x)
103104
assert.False(b, r.HasErrors(), fmt.Sprintf("unexpected validation error: %v", r.AsError()))
104-
r.ApplyDefaults()
105+
ApplyDefaults(r)
105106
}
106107
}
107108

0 commit comments

Comments
 (0)