forked from stripe/stripe-mock
-
Notifications
You must be signed in to change notification settings - Fork 0
/
validate.go
130 lines (121 loc) · 3.96 KB
/
validate.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package spec
import (
"github.com/lestrrat-go/jsschema"
"github.com/lestrrat-go/jsval"
"github.com/lestrrat-go/jsval/builder"
)
// ComponentsForValidation is a collection of components for an OpenAPI
// specification that's been translated into equivalent JSON Schemas.
type ComponentsForValidation struct {
root interface{}
}
// GetValidatorForOpenAPI3Schema gets a JSON Schema validator for a given
// OpenAPI specification and set of JSON Schema components.
func GetValidatorForOpenAPI3Schema(oaiSchema *Schema, components *ComponentsForValidation) (*jsval.JSVal, error) {
jsonSchemaAsJSON := getJSONSchemaForOpenAPI3Schema(oaiSchema)
jsonSchema := schema.New()
err := jsonSchema.Extract(jsonSchemaAsJSON)
if err != nil {
return nil, err
}
if components == nil {
components = &ComponentsForValidation{root: make(map[string]interface{})}
}
validatorBuilder := builder.New()
validator, err := validatorBuilder.BuildWithCtx(jsonSchema, components.root)
if err != nil {
return nil, err
}
return validator, nil
}
// GetComponentsForValidation translates a collection of components for an
// OpenAPI specification into equivalent JSON schemas.
//
// See also the comment on getJSONSchemaForOpenAPI3Schema.
func GetComponentsForValidation(components *Components) *ComponentsForValidation {
jsonSchemas := make(map[string]interface{})
for name, oaiSchema := range components.Schemas {
jsonSchemas[name] = getJSONSchemaForOpenAPI3Schema(oaiSchema)
}
return &ComponentsForValidation{
root: map[string]interface{}{
"components": map[string]interface{}{
"schemas": jsonSchemas,
},
},
}
}
// Given an OpenAPI 3 schema represented as JSON, returns an equivalent JSON
// Schema represented as JSON. The important difference between OpenAPI 3
// schemas and JSON schemas is that OpenAPI 3 uses "nullable: true" to mark
// values that can be null, whereas JSON schemas represent "null" as a type just
// like "string".
//
// This converter only handles the options that are supported by the spec.Schema
// type, and it must be updated when new options are supported.
func getJSONSchemaForOpenAPI3Schema(oai *Schema) map[string]interface{} {
jss := make(map[string]interface{})
if oai.AdditionalProperties != nil {
// We currently don't decode `AdditionalProperties` into a custom
// struct, so it's a pretty direct JSON representation. Just set it
// directly.
jss["additionalProperties"] = oai.AdditionalProperties
}
if len(oai.AnyOf) != 0 {
var jssAnyOf = make([]interface{}, len(oai.AnyOf))
for index, oaiSubschema := range oai.AnyOf {
jssAnyOf[index] = getJSONSchemaForOpenAPI3Schema(oaiSubschema)
}
if oai.Nullable {
jssAnyOf = append(jssAnyOf, map[string]interface{}{"const": nil})
}
jss["anyOf"] = jssAnyOf
}
if len(oai.Enum) != 0 {
var jssEnum = make([]interface{}, len(oai.Enum))
for index, oaiValue := range oai.Enum {
jssEnum[index] = oaiValue
}
jss["enum"] = jssEnum
}
if oai.Format != "" {
// Note that the major format that will be seen here, unix-time, will
// not be supported by the validator we're using -- we should probably
// see if we can support that properly.
jss["format"] = oai.Format
}
if oai.Items != nil {
jss["items"] = getJSONSchemaForOpenAPI3Schema(oai.Items)
}
if oai.MaxLength != 0 {
jss["maxLength"] = oai.MaxLength
}
if oai.Pattern != "" {
jss["pattern"] = oai.Pattern
}
if len(oai.Properties) != 0 {
var jssProperties = make(map[string]interface{})
for key, oaiSubschema := range oai.Properties {
jssProperties[key] = getJSONSchemaForOpenAPI3Schema(oaiSubschema)
}
jss["properties"] = jssProperties
}
if len(oai.Required) != 0 {
var jssRequired = make([]interface{}, len(oai.Required))
for index, oaiValue := range oai.Required {
jssRequired[index] = oaiValue
}
jss["required"] = jssRequired
}
if oai.Type != "" {
if oai.Nullable {
jss["type"] = []interface{}{oai.Type, "null"}
} else {
jss["type"] = oai.Type
}
}
if oai.Ref != "" {
jss["$ref"] = oai.Ref
}
return jss
}