-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathread.go
146 lines (133 loc) · 3.41 KB
/
read.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package openapi3
import (
"fmt"
"io"
"net/http"
"os"
"regexp"
"strings"
oas3 "github.com/getkin/kin-openapi/openapi3"
"github.com/grokify/mogo/encoding/jsonutil"
"github.com/grokify/mogo/errors/errorsutil"
"sigs.k8s.io/yaml"
)
var rxYamlExtension = regexp.MustCompile(`(?i)\.ya?ml\s*$`)
func ReadURL(oas3url string) (*Spec, error) {
resp, err := http.Get(oas3url) // #nosec G107
if err != nil {
return nil, err
}
bytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return Parse(bytes)
}
// ReadFile does optional validation which is useful when
// merging incomplete spec files.
func ReadFile(oas3file string, validate bool) (*Spec, error) {
if validate {
return readAndValidateFile(oas3file)
}
bytes, err := os.ReadFile(oas3file)
if err != nil {
return nil, errorsutil.Wrapf(err, "ReadFile.ReadFile.Error.Filename file: (%v)", oas3file)
}
if rxYamlExtension.MatchString(oas3file) {
bytes, err = yaml.YAMLToJSON(bytes)
if err != nil {
return nil, err
}
}
spec := &Spec{}
err = spec.UnmarshalJSON(bytes)
if err != nil {
return nil, errorsutil.Wrapf(err, "error ReadFile.UnmarshalJSON.Error.Filename file: (%s) ", oas3file)
}
return spec, nil
}
func readAndValidateFile(oas3file string) (*Spec, error) {
data, err := os.ReadFile(oas3file)
if err != nil {
return nil, errorsutil.Wrap(err, "E_READ_FILE_ERROR")
}
return readAndValidateBytes(data)
}
func readAndValidateBytes(b []byte) (*Spec, error) {
spec, err := oas3.NewLoader().LoadFromData(b)
if err != nil {
return spec, errorsutil.Wrap(err, "error `oas3.NewLoader().LoadFromData(bytes)`")
}
_, err = validateMore(spec)
return spec, err
}
// Parse will parse a byte array to an `*oas3.Swagger` struct.
// It will use JSON first. If unsuccessful, it will attempt to
// parse it as YAML.
func Parse(oas3Bytes []byte) (*Spec, error) {
spec := &Spec{}
err := spec.UnmarshalJSON(oas3Bytes)
if err != nil {
bytes, err2 := yaml.YAMLToJSON(oas3Bytes)
if err2 != nil {
return spec, err
}
spec = &Spec{}
err3 := spec.UnmarshalJSON(bytes)
return spec, err3
}
return spec, err
}
type ValidationStatus struct {
Status bool
Message string
Context string
OpenAPI string
}
func validateMore(spec *Spec) (ValidationStatus, error) {
vs := ValidationStatus{}
if spec == nil {
return vs, ErrSpecNotSet
}
version := ""
if spec.Info == nil {
vs := ValidationStatus{
Context: "#/info",
Message: "expect spec to have info object)",
OpenAPI: spec.OpenAPI}
return vs, fmt.Errorf("E_OPENAPI3_MISSING_KEY [%s]", "info")
} else {
version = strings.TrimSpace(spec.Info.Version)
if len(strings.TrimSpace(version)) == 0 {
version = OASVersionDefault
}
vs.OpenAPI = version
if len(version) == 0 {
jdata, err := jsonutil.MarshalSimple(spec.Info, "", " ")
if err != nil {
return vs, err
}
vs := ValidationStatus{
Context: "#/info",
Message: fmt.Sprintf("expect Object %s to have key version\nmissing keys:version", string(jdata)),
OpenAPI: spec.OpenAPI}
return vs, fmt.Errorf("E_OPENAPI3_MISSING_KEY [%s]", "info/version")
}
vs.Status = true
}
return vs, nil
}
func (sm *SpecMore) ValidateMore() (ValidationStatus, error) {
if sm.Spec == nil {
return ValidationStatus{}, ErrSpecNotSet
}
return validateMore(sm.Spec)
}
func (sm *SpecMore) Validate() error {
jbytes, err := sm.MarshalJSON("", "")
if err != nil {
return err
}
_, err = readAndValidateBytes(jbytes)
return err
}