Skip to content

Commit de2455e

Browse files
authored
openapi3: unexport ValidationOptions fields and add some more (#717)
1 parent 3be535f commit de2455e

File tree

8 files changed

+148
-19
lines changed

8 files changed

+148
-19
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ Be sure to check [OpenAPI Initiative](https://github.com/OAI)'s [great tooling l
5555
* Generates `*openapi3.Schema` values for Go types.
5656

5757
# Some recipes
58+
## Validating an OpenAPI document
59+
```shell
60+
go run github.com/getkin/kin-openapi/cmd/validate@latest [--defaults] [--examples] [--ext] [--patterns] -- <local YAML or JSON file>
61+
```
62+
5863
## Loading OpenAPI document
5964
Use `openapi3.Loader`, which resolves all references:
6065
```go
@@ -196,6 +201,11 @@ func arrayUniqueItemsChecker(items []interface{}) bool {
196201

197202
## Sub-v0 breaking API changes
198203

204+
### v0.112.0
205+
* `(openapi3.ValidationOptions).ExamplesValidationDisabled` has been unexported.
206+
* `(openapi3.ValidationOptions).SchemaFormatValidationEnabled` has been unexported.
207+
* `(openapi3.ValidationOptions).SchemaPatternValidationDisabled` has been unexported.
208+
199209
### v0.111.0
200210
* Changed `func (*_) Validate(ctx context.Context) error` to `func (*_) Validate(ctx context.Context, opts ...ValidationOption) error`.
201211
* `openapi3.WithValidationOptions(ctx context.Context, opts *ValidationOptions) context.Context` prototype changed to `openapi3.WithValidationOptions(ctx context.Context, opts ...ValidationOption) context.Context`.

cmd/validate/main.go

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"log"
6+
"os"
7+
"strings"
8+
9+
"github.com/invopop/yaml"
10+
11+
"github.com/getkin/kin-openapi/openapi2"
12+
"github.com/getkin/kin-openapi/openapi3"
13+
)
14+
15+
var (
16+
defaultDefaults = true
17+
defaults = flag.Bool("defaults", defaultDefaults, "when false, disables schemas' default field validation")
18+
)
19+
20+
var (
21+
defaultExamples = true
22+
examples = flag.Bool("examples", defaultExamples, "when false, disables all example schema validation")
23+
)
24+
25+
var (
26+
defaultExt = false
27+
ext = flag.Bool("ext", defaultExt, "enables visiting other files")
28+
)
29+
30+
var (
31+
defaultPatterns = true
32+
patterns = flag.Bool("patterns", defaultPatterns, "when false, allows schema patterns unsupported by the Go regexp engine")
33+
)
34+
35+
func main() {
36+
flag.Parse()
37+
filename := flag.Arg(0)
38+
if len(flag.Args()) != 1 || filename == "" {
39+
log.Fatalf("Usage: go run github.com/getkin/kin-openapi/cmd/validate@latest [--defaults] [--examples] [--ext] [--patterns] -- <local YAML or JSON file>\nGot: %+v\n", os.Args)
40+
}
41+
42+
data, err := os.ReadFile(filename)
43+
if err != nil {
44+
log.Fatal(err)
45+
}
46+
47+
var vd struct {
48+
OpenAPI string `json:"openapi" yaml:"openapi"`
49+
Swagger string `json:"swagger" yaml:"swagger"`
50+
}
51+
if err := yaml.Unmarshal(data, &vd); err != nil {
52+
log.Fatal(err)
53+
}
54+
55+
switch {
56+
case vd.OpenAPI == "3" || strings.HasPrefix(vd.OpenAPI, "3."):
57+
loader := openapi3.NewLoader()
58+
loader.IsExternalRefsAllowed = *ext
59+
60+
doc, err := loader.LoadFromFile(filename)
61+
if err != nil {
62+
log.Fatal(err)
63+
}
64+
65+
var opts []openapi3.ValidationOption
66+
if !*defaults {
67+
opts = append(opts, openapi3.DisableSchemaDefaultsValidation())
68+
}
69+
if !*examples {
70+
opts = append(opts, openapi3.DisableExamplesValidation())
71+
}
72+
if !*patterns {
73+
opts = append(opts, openapi3.DisableSchemaPatternValidation())
74+
}
75+
76+
if err = doc.Validate(loader.Context, opts...); err != nil {
77+
log.Fatal(err)
78+
}
79+
80+
case vd.Swagger == "2" || strings.HasPrefix(vd.Swagger, "2."):
81+
if *defaults != defaultDefaults {
82+
log.Fatal("Flag --defaults is only for OpenAPIv3")
83+
}
84+
if *examples != defaultExamples {
85+
log.Fatal("Flag --examples is only for OpenAPIv3")
86+
}
87+
if *ext != defaultExt {
88+
log.Fatal("Flag --ext is only for OpenAPIv3")
89+
}
90+
if *patterns != defaultPatterns {
91+
log.Fatal("Flag --patterns is only for OpenAPIv3")
92+
}
93+
94+
var doc openapi2.T
95+
if err := yaml.Unmarshal(data, &doc); err != nil {
96+
log.Fatal(err)
97+
}
98+
99+
default:
100+
log.Fatal("Missing or incorrect 'openapi' or 'swagger' field")
101+
}
102+
}

openapi3/media_type.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (mediaType *MediaType) Validate(ctx context.Context, opts ...ValidationOpti
9090
return errors.New("example and examples are mutually exclusive")
9191
}
9292

93-
if vo := getValidationOptions(ctx); vo.ExamplesValidationDisabled {
93+
if vo := getValidationOptions(ctx); vo.examplesValidationDisabled {
9494
return nil
9595
}
9696

openapi3/parameter.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,7 @@ func (parameter *Parameter) Validate(ctx context.Context, opts ...ValidationOpti
323323
return fmt.Errorf("parameter %q example and examples are mutually exclusive", parameter.Name)
324324
}
325325

326-
if vo := getValidationOptions(ctx); vo.ExamplesValidationDisabled {
326+
if vo := getValidationOptions(ctx); vo.examplesValidationDisabled {
327327
return nil
328328
}
329329
if example := parameter.Example; example != nil {

openapi3/request_body.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ func (requestBody *RequestBody) Validate(ctx context.Context, opts ...Validation
112112
return errors.New("content of the request body is required")
113113
}
114114

115-
if vo := getValidationOptions(ctx); !vo.ExamplesValidationDisabled {
115+
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
116116
vo.examplesValidationAsReq, vo.examplesValidationAsRes = true, false
117117
}
118118

openapi3/response.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (response *Response) Validate(ctx context.Context, opts ...ValidationOption
119119
if response.Description == nil {
120120
return errors.New("a short description of the response is required")
121121
}
122-
if vo := getValidationOptions(ctx); !vo.ExamplesValidationDisabled {
122+
if vo := getValidationOptions(ctx); !vo.examplesValidationDisabled {
123123
vo.examplesValidationAsReq, vo.examplesValidationAsRes = false, true
124124
}
125125

openapi3/schema.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
678678
switch format {
679679
case "float", "double":
680680
default:
681-
if validationOpts.SchemaFormatValidationEnabled {
681+
if validationOpts.schemaFormatValidationEnabled {
682682
return unsupportedFormat(format)
683683
}
684684
}
@@ -688,7 +688,7 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
688688
switch format {
689689
case "int32", "int64":
690690
default:
691-
if validationOpts.SchemaFormatValidationEnabled {
691+
if validationOpts.schemaFormatValidationEnabled {
692692
return unsupportedFormat(format)
693693
}
694694
}
@@ -710,12 +710,12 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
710710
case "email", "hostname", "ipv4", "ipv6", "uri", "uri-reference":
711711
default:
712712
// Try to check for custom defined formats
713-
if _, ok := SchemaStringFormats[format]; !ok && validationOpts.SchemaFormatValidationEnabled {
713+
if _, ok := SchemaStringFormats[format]; !ok && validationOpts.schemaFormatValidationEnabled {
714714
return unsupportedFormat(format)
715715
}
716716
}
717717
}
718-
if schema.Pattern != "" && !validationOpts.SchemaPatternValidationDisabled {
718+
if schema.Pattern != "" && !validationOpts.schemaPatternValidationDisabled {
719719
if err = schema.compilePattern(); err != nil {
720720
return err
721721
}
@@ -771,13 +771,13 @@ func (schema *Schema) validate(ctx context.Context, stack []*Schema) (err error)
771771
}
772772
}
773773

774-
if v := schema.Default; v != nil {
774+
if v := schema.Default; v != nil && !validationOpts.schemaDefaultsValidationDisabled {
775775
if err := schema.VisitJSON(v); err != nil {
776776
return fmt.Errorf("invalid default: %w", err)
777777
}
778778
}
779779

780-
if x := schema.Example; x != nil && !validationOpts.ExamplesValidationDisabled {
780+
if x := schema.Example; x != nil && !validationOpts.examplesValidationDisabled {
781781
if err := validateExampleValue(ctx, x, schema); err != nil {
782782
return fmt.Errorf("invalid example: %w", err)
783783
}

openapi3/validation_options.go

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ type ValidationOption func(options *ValidationOptions)
77

88
// ValidationOptions provides configuration for validating OpenAPI documents.
99
type ValidationOptions struct {
10-
SchemaFormatValidationEnabled bool
11-
SchemaPatternValidationDisabled bool
12-
ExamplesValidationDisabled bool
1310
examplesValidationAsReq, examplesValidationAsRes bool
11+
examplesValidationDisabled bool
12+
schemaDefaultsValidationDisabled bool
13+
schemaFormatValidationEnabled bool
14+
schemaPatternValidationDisabled bool
1415
}
1516

1617
type validationOptionsKey struct{}
@@ -19,46 +20,62 @@ type validationOptionsKey struct{}
1920
// By default, schema format validation is disabled.
2021
func EnableSchemaFormatValidation() ValidationOption {
2122
return func(options *ValidationOptions) {
22-
options.SchemaFormatValidationEnabled = true
23+
options.schemaFormatValidationEnabled = true
2324
}
2425
}
2526

2627
// DisableSchemaFormatValidation does the opposite of EnableSchemaFormatValidation.
2728
// By default, schema format validation is disabled.
2829
func DisableSchemaFormatValidation() ValidationOption {
2930
return func(options *ValidationOptions) {
30-
options.SchemaFormatValidationEnabled = false
31+
options.schemaFormatValidationEnabled = false
3132
}
3233
}
3334

3435
// EnableSchemaPatternValidation does the opposite of DisableSchemaPatternValidation.
3536
// By default, schema pattern validation is enabled.
3637
func EnableSchemaPatternValidation() ValidationOption {
3738
return func(options *ValidationOptions) {
38-
options.SchemaPatternValidationDisabled = false
39+
options.schemaPatternValidationDisabled = false
3940
}
4041
}
4142

4243
// DisableSchemaPatternValidation makes Validate not return an error when validating patterns that are not supported by the Go regexp engine.
4344
func DisableSchemaPatternValidation() ValidationOption {
4445
return func(options *ValidationOptions) {
45-
options.SchemaPatternValidationDisabled = true
46+
options.schemaPatternValidationDisabled = true
47+
}
48+
}
49+
50+
// EnableSchemaDefaultsValidation does the opposite of DisableSchemaDefaultsValidation.
51+
// By default, schema default values are validated against their schema.
52+
func EnableSchemaDefaultsValidation() ValidationOption {
53+
return func(options *ValidationOptions) {
54+
options.schemaDefaultsValidationDisabled = false
55+
}
56+
}
57+
58+
// DisableSchemaDefaultsValidation disables schemas' default field validation.
59+
// By default, schema default values are validated against their schema.
60+
func DisableSchemaDefaultsValidation() ValidationOption {
61+
return func(options *ValidationOptions) {
62+
options.schemaDefaultsValidationDisabled = true
4663
}
4764
}
4865

4966
// EnableExamplesValidation does the opposite of DisableExamplesValidation.
5067
// By default, all schema examples are validated.
5168
func EnableExamplesValidation() ValidationOption {
5269
return func(options *ValidationOptions) {
53-
options.ExamplesValidationDisabled = false
70+
options.examplesValidationDisabled = false
5471
}
5572
}
5673

5774
// DisableExamplesValidation disables all example schema validation.
5875
// By default, all schema examples are validated.
5976
func DisableExamplesValidation() ValidationOption {
6077
return func(options *ValidationOptions) {
61-
options.ExamplesValidationDisabled = true
78+
options.examplesValidationDisabled = true
6279
}
6380
}
6481

0 commit comments

Comments
 (0)