-
Notifications
You must be signed in to change notification settings - Fork 28
/
read.go
129 lines (118 loc) · 3.13 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
package openapi3
import (
"fmt"
"io/ioutil"
"net/http"
"regexp"
"strings"
oas3 "github.com/getkin/kin-openapi/openapi3"
"github.com/ghodss/yaml"
"github.com/grokify/simplego/encoding/jsonutil"
"github.com/pkg/errors"
)
var rxYamlExtension = regexp.MustCompile(`(?i)\.ya?ml\s*$`)
func ReadURL(oas3url string) (*oas3.Swagger, error) {
resp, err := http.Get(oas3url)
if err != nil {
return nil, err
}
bytes, err := ioutil.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) (*oas3.Swagger, error) {
if validate {
return ReadAndValidateFile(oas3file)
}
bytes, err := ioutil.ReadFile(oas3file)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("ReadFile.ReadFile.Error.Filename [%v]", oas3file))
}
if rxYamlExtension.MatchString(oas3file) {
bytes, err = yaml.YAMLToJSON(bytes)
if err != nil {
return nil, err
}
}
spec := &oas3.Swagger{}
err = spec.UnmarshalJSON(bytes)
if err != nil {
return nil, errors.Wrap(err, fmt.Sprintf("ReadFile.UnmarshalJSON.Error.Filename [%s]", oas3file))
}
return spec, nil
}
// 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) (*oas3.Swagger, error) {
spec := &oas3.Swagger{}
err := spec.UnmarshalJSON(oas3Bytes)
if err != nil {
bytes, err2 := yaml.YAMLToJSON(oas3Bytes)
if err2 != nil {
return spec, err
}
spec = &oas3.Swagger{}
err3 := spec.UnmarshalJSON(bytes)
return spec, err3
}
return spec, err
}
func ReadAndValidateFile(oas3file string) (*oas3.Swagger, error) {
bytes, err := ioutil.ReadFile(oas3file)
if err != nil {
return nil, errors.Wrap(err, "E_READ_FILE_ERROR")
}
spec, err := oas3.NewSwaggerLoader().LoadSwaggerFromData(bytes)
if err != nil {
return spec, errors.Wrap(err, fmt.Sprintf("E_OPENAPI3_SPEC_LOAD_VALIDATE_ERROR [%s]", oas3file))
}
_, err = ValidateMore(spec)
return spec, err
}
type ValidationStatus struct {
Status bool
Message string
Context string
OpenAPI string
}
/*
status: false
message: |-
expected Object {
title: 'Medium API',
description: 'Articles that matter on social publishing platform'
} to have key version
missing keys: version
context: "#/info"
openapi: 3.0.0
*/
func ValidateMore(spec *oas3.Swagger) (ValidationStatus, error) {
vs := ValidationStatus{OpenAPI: "3.0.0"}
version := strings.TrimSpace(spec.Info.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: "3.0.0"}
return vs, fmt.Errorf("E_OPENAPI3_MISSING_KEY [%s]", "info/version")
}
vs.Status = true
return vs, nil
}
func Copy(spec *oas3.Swagger) (*oas3.Swagger, error) {
bytes, err := spec.MarshalJSON()
if err != nil {
return nil, err
}
loader := oas3.NewSwaggerLoader()
return loader.LoadSwaggerFromData(bytes)
}