blob: 1405bfd8ee2b01f378a695f9e6652459a742c29f [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// Copyright 2015 go-swagger maintainers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package spec
16
17import (
18 "encoding/json"
19 "net/http"
20 "os"
21 "path/filepath"
22
23 "github.com/go-openapi/jsonreference"
24)
25
26// Refable is a struct for things that accept a $ref property
27type Refable struct {
28 Ref Ref
29}
30
31// MarshalJSON marshals the ref to json
32func (r Refable) MarshalJSON() ([]byte, error) {
33 return r.Ref.MarshalJSON()
34}
35
36// UnmarshalJSON unmarshalss the ref from json
37func (r *Refable) UnmarshalJSON(d []byte) error {
38 return json.Unmarshal(d, &r.Ref)
39}
40
41// Ref represents a json reference that is potentially resolved
42type Ref struct {
43 jsonreference.Ref
44}
45
46// RemoteURI gets the remote uri part of the ref
47func (r *Ref) RemoteURI() string {
48 if r.String() == "" {
49 return r.String()
50 }
51
52 u := *r.GetURL()
53 u.Fragment = ""
54 return u.String()
55}
56
57// IsValidURI returns true when the url the ref points to can be found
58func (r *Ref) IsValidURI(basepaths ...string) bool {
59 if r.String() == "" {
60 return true
61 }
62
63 v := r.RemoteURI()
64 if v == "" {
65 return true
66 }
67
68 if r.HasFullURL {
69 rr, err := http.Get(v)
70 if err != nil {
71 return false
72 }
73
74 return rr.StatusCode/100 == 2
75 }
76
77 if !(r.HasFileScheme || r.HasFullFilePath || r.HasURLPathOnly) {
78 return false
79 }
80
81 // check for local file
82 pth := v
83 if r.HasURLPathOnly {
84 base := "."
85 if len(basepaths) > 0 {
86 base = filepath.Dir(filepath.Join(basepaths...))
87 }
88 p, e := filepath.Abs(filepath.ToSlash(filepath.Join(base, pth)))
89 if e != nil {
90 return false
91 }
92 pth = p
93 }
94
95 fi, err := os.Stat(filepath.ToSlash(pth))
96 if err != nil {
97 return false
98 }
99
100 return !fi.IsDir()
101}
102
103// Inherits creates a new reference from a parent and a child
104// If the child cannot inherit from the parent, an error is returned
105func (r *Ref) Inherits(child Ref) (*Ref, error) {
106 ref, err := r.Ref.Inherits(child.Ref)
107 if err != nil {
108 return nil, err
109 }
110 return &Ref{Ref: *ref}, nil
111}
112
113// NewRef creates a new instance of a ref object
114// returns an error when the reference uri is an invalid uri
115func NewRef(refURI string) (Ref, error) {
116 ref, err := jsonreference.New(refURI)
117 if err != nil {
118 return Ref{}, err
119 }
120 return Ref{Ref: ref}, nil
121}
122
123// MustCreateRef creates a ref object but panics when refURI is invalid.
124// Use the NewRef method for a version that returns an error.
125func MustCreateRef(refURI string) Ref {
126 return Ref{Ref: jsonreference.MustCreateRef(refURI)}
127}
128
129// MarshalJSON marshals this ref into a JSON object
130func (r Ref) MarshalJSON() ([]byte, error) {
131 str := r.String()
132 if str == "" {
133 if r.IsRoot() {
134 return []byte(`{"$ref":""}`), nil
135 }
136 return []byte("{}"), nil
137 }
138 v := map[string]interface{}{"$ref": str}
139 return json.Marshal(v)
140}
141
142// UnmarshalJSON unmarshals this ref from a JSON object
143func (r *Ref) UnmarshalJSON(d []byte) error {
144 var v map[string]interface{}
145 if err := json.Unmarshal(d, &v); err != nil {
146 return err
147 }
148 return r.fromMap(v)
149}
150
151func (r *Ref) fromMap(v map[string]interface{}) error {
152 if v == nil {
153 return nil
154 }
155
156 if vv, ok := v["$ref"]; ok {
157 if str, ok := vv.(string); ok {
158 ref, err := jsonreference.New(str)
159 if err != nil {
160 return err
161 }
162 *r = Ref{Ref: ref}
163 }
164 }
165
166 return nil
167}