expander.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. // 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. package spec
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "net/url"
  19. "reflect"
  20. "strings"
  21. "sync"
  22. "github.com/go-openapi/jsonpointer"
  23. "github.com/go-openapi/swag"
  24. )
  25. // ResolutionCache a cache for resolving urls
  26. type ResolutionCache interface {
  27. Get(string) (interface{}, bool)
  28. Set(string, interface{})
  29. }
  30. type simpleCache struct {
  31. lock sync.Mutex
  32. store map[string]interface{}
  33. }
  34. var resCache = initResolutionCache()
  35. func initResolutionCache() ResolutionCache {
  36. return &simpleCache{store: map[string]interface{}{
  37. "http://swagger.io/v2/schema.json": MustLoadSwagger20Schema(),
  38. "http://json-schema.org/draft-04/schema": MustLoadJSONSchemaDraft04(),
  39. }}
  40. }
  41. func (s *simpleCache) Get(uri string) (interface{}, bool) {
  42. s.lock.Lock()
  43. v, ok := s.store[uri]
  44. s.lock.Unlock()
  45. return v, ok
  46. }
  47. func (s *simpleCache) Set(uri string, data interface{}) {
  48. s.lock.Lock()
  49. s.store[uri] = data
  50. s.lock.Unlock()
  51. }
  52. // ResolveRef resolves a reference against a context root
  53. func ResolveRef(root interface{}, ref *Ref) (*Schema, error) {
  54. resolver, err := defaultSchemaLoader(root, nil, nil)
  55. if err != nil {
  56. return nil, err
  57. }
  58. result := new(Schema)
  59. if err := resolver.Resolve(ref, result); err != nil {
  60. return nil, err
  61. }
  62. return result, nil
  63. }
  64. // ResolveParameter resolves a paramter reference against a context root
  65. func ResolveParameter(root interface{}, ref Ref) (*Parameter, error) {
  66. resolver, err := defaultSchemaLoader(root, nil, nil)
  67. if err != nil {
  68. return nil, err
  69. }
  70. result := new(Parameter)
  71. if err := resolver.Resolve(&ref, result); err != nil {
  72. return nil, err
  73. }
  74. return result, nil
  75. }
  76. // ResolveResponse resolves response a reference against a context root
  77. func ResolveResponse(root interface{}, ref Ref) (*Response, error) {
  78. resolver, err := defaultSchemaLoader(root, nil, nil)
  79. if err != nil {
  80. return nil, err
  81. }
  82. result := new(Response)
  83. if err := resolver.Resolve(&ref, result); err != nil {
  84. return nil, err
  85. }
  86. return result, nil
  87. }
  88. type schemaLoader struct {
  89. loadingRef *Ref
  90. startingRef *Ref
  91. currentRef *Ref
  92. root interface{}
  93. cache ResolutionCache
  94. loadDoc func(string) (json.RawMessage, error)
  95. }
  96. var idPtr, _ = jsonpointer.New("/id")
  97. var schemaPtr, _ = jsonpointer.New("/$schema")
  98. var refPtr, _ = jsonpointer.New("/$ref")
  99. func defaultSchemaLoader(root interface{}, ref *Ref, cache ResolutionCache) (*schemaLoader, error) {
  100. if cache == nil {
  101. cache = resCache
  102. }
  103. var ptr *jsonpointer.Pointer
  104. if ref != nil {
  105. ptr = ref.GetPointer()
  106. }
  107. currentRef := nextRef(root, ref, ptr)
  108. return &schemaLoader{
  109. root: root,
  110. loadingRef: ref,
  111. startingRef: ref,
  112. cache: cache,
  113. loadDoc: func(path string) (json.RawMessage, error) {
  114. data, err := swag.LoadFromFileOrHTTP(path)
  115. if err != nil {
  116. return nil, err
  117. }
  118. return json.RawMessage(data), nil
  119. },
  120. currentRef: currentRef,
  121. }, nil
  122. }
  123. func idFromNode(node interface{}) (*Ref, error) {
  124. if idValue, _, err := idPtr.Get(node); err == nil {
  125. if refStr, ok := idValue.(string); ok && refStr != "" {
  126. idRef, err := NewRef(refStr)
  127. if err != nil {
  128. return nil, err
  129. }
  130. return &idRef, nil
  131. }
  132. }
  133. return nil, nil
  134. }
  135. func nextRef(startingNode interface{}, startingRef *Ref, ptr *jsonpointer.Pointer) *Ref {
  136. if startingRef == nil {
  137. return nil
  138. }
  139. if ptr == nil {
  140. return startingRef
  141. }
  142. ret := startingRef
  143. var idRef *Ref
  144. node := startingNode
  145. for _, tok := range ptr.DecodedTokens() {
  146. node, _, _ = jsonpointer.GetForToken(node, tok)
  147. if node == nil {
  148. break
  149. }
  150. idRef, _ = idFromNode(node)
  151. if idRef != nil {
  152. nw, err := ret.Inherits(*idRef)
  153. if err != nil {
  154. break
  155. }
  156. ret = nw
  157. }
  158. refRef, _, _ := refPtr.Get(node)
  159. if refRef != nil {
  160. rf, _ := NewRef(refRef.(string))
  161. nw, err := ret.Inherits(rf)
  162. if err != nil {
  163. break
  164. }
  165. ret = nw
  166. }
  167. }
  168. return ret
  169. }
  170. func (r *schemaLoader) resolveRef(currentRef, ref *Ref, node, target interface{}) error {
  171. tgt := reflect.ValueOf(target)
  172. if tgt.Kind() != reflect.Ptr {
  173. return fmt.Errorf("resolve ref: target needs to be a pointer")
  174. }
  175. oldRef := currentRef
  176. if currentRef != nil {
  177. var err error
  178. currentRef, err = currentRef.Inherits(*nextRef(node, ref, currentRef.GetPointer()))
  179. if err != nil {
  180. return err
  181. }
  182. }
  183. if currentRef == nil {
  184. currentRef = ref
  185. }
  186. refURL := currentRef.GetURL()
  187. if refURL == nil {
  188. return nil
  189. }
  190. if currentRef.IsRoot() {
  191. nv := reflect.ValueOf(node)
  192. reflect.Indirect(tgt).Set(reflect.Indirect(nv))
  193. return nil
  194. }
  195. if strings.HasPrefix(refURL.String(), "#") {
  196. res, _, err := ref.GetPointer().Get(node)
  197. if err != nil {
  198. res, _, err = ref.GetPointer().Get(r.root)
  199. if err != nil {
  200. return err
  201. }
  202. }
  203. rv := reflect.Indirect(reflect.ValueOf(res))
  204. tgtType := reflect.Indirect(tgt).Type()
  205. if rv.Type().AssignableTo(tgtType) {
  206. reflect.Indirect(tgt).Set(reflect.Indirect(reflect.ValueOf(res)))
  207. } else {
  208. if err := swag.DynamicJSONToStruct(rv.Interface(), target); err != nil {
  209. return err
  210. }
  211. }
  212. return nil
  213. }
  214. if refURL.Scheme != "" && refURL.Host != "" {
  215. // most definitely take the red pill
  216. data, _, _, err := r.load(refURL)
  217. if err != nil {
  218. return err
  219. }
  220. if ((oldRef == nil && currentRef != nil) ||
  221. (oldRef != nil && currentRef == nil) ||
  222. oldRef.String() != currentRef.String()) &&
  223. ((oldRef == nil && ref != nil) ||
  224. (oldRef != nil && ref == nil) ||
  225. (oldRef.String() != ref.String())) {
  226. return r.resolveRef(currentRef, ref, data, target)
  227. }
  228. var res interface{}
  229. if currentRef.String() != "" {
  230. res, _, err = currentRef.GetPointer().Get(data)
  231. if err != nil {
  232. return err
  233. }
  234. } else {
  235. res = data
  236. }
  237. if err := swag.DynamicJSONToStruct(res, target); err != nil {
  238. return err
  239. }
  240. }
  241. return nil
  242. }
  243. func (r *schemaLoader) load(refURL *url.URL) (interface{}, url.URL, bool, error) {
  244. toFetch := *refURL
  245. toFetch.Fragment = ""
  246. data, fromCache := r.cache.Get(toFetch.String())
  247. if !fromCache {
  248. b, err := r.loadDoc(toFetch.String())
  249. if err != nil {
  250. return nil, url.URL{}, false, err
  251. }
  252. if err := json.Unmarshal(b, &data); err != nil {
  253. return nil, url.URL{}, false, err
  254. }
  255. r.cache.Set(toFetch.String(), data)
  256. }
  257. return data, toFetch, fromCache, nil
  258. }
  259. func (r *schemaLoader) Resolve(ref *Ref, target interface{}) error {
  260. if err := r.resolveRef(r.currentRef, ref, r.root, target); err != nil {
  261. return err
  262. }
  263. return nil
  264. }
  265. type specExpander struct {
  266. spec *Swagger
  267. resolver *schemaLoader
  268. }
  269. // ExpandSpec expands the references in a swagger spec
  270. func ExpandSpec(spec *Swagger) error {
  271. resolver, err := defaultSchemaLoader(spec, nil, nil)
  272. if err != nil {
  273. return err
  274. }
  275. for key, defintition := range spec.Definitions {
  276. var def *Schema
  277. var err error
  278. if def, err = expandSchema(defintition, []string{"#/definitions/" + key}, resolver); err != nil {
  279. return err
  280. }
  281. spec.Definitions[key] = *def
  282. }
  283. for key, parameter := range spec.Parameters {
  284. if err := expandParameter(&parameter, resolver); err != nil {
  285. return err
  286. }
  287. spec.Parameters[key] = parameter
  288. }
  289. for key, response := range spec.Responses {
  290. if err := expandResponse(&response, resolver); err != nil {
  291. return err
  292. }
  293. spec.Responses[key] = response
  294. }
  295. if spec.Paths != nil {
  296. for key, path := range spec.Paths.Paths {
  297. if err := expandPathItem(&path, resolver); err != nil {
  298. return err
  299. }
  300. spec.Paths.Paths[key] = path
  301. }
  302. }
  303. return nil
  304. }
  305. // ExpandSchema expands the refs in the schema object
  306. func ExpandSchema(schema *Schema, root interface{}, cache ResolutionCache) error {
  307. if schema == nil {
  308. return nil
  309. }
  310. if root == nil {
  311. root = schema
  312. }
  313. nrr, _ := NewRef(schema.ID)
  314. var rrr *Ref
  315. if nrr.String() != "" {
  316. switch root.(type) {
  317. case *Schema:
  318. rid, _ := NewRef(root.(*Schema).ID)
  319. rrr, _ = rid.Inherits(nrr)
  320. case *Swagger:
  321. rid, _ := NewRef(root.(*Swagger).ID)
  322. rrr, _ = rid.Inherits(nrr)
  323. }
  324. }
  325. resolver, err := defaultSchemaLoader(root, rrr, cache)
  326. if err != nil {
  327. return err
  328. }
  329. refs := []string{""}
  330. if rrr != nil {
  331. refs[0] = rrr.String()
  332. }
  333. var s *Schema
  334. if s, err = expandSchema(*schema, refs, resolver); err != nil {
  335. return nil
  336. }
  337. *schema = *s
  338. return nil
  339. }
  340. func expandItems(target Schema, parentRefs []string, resolver *schemaLoader) (*Schema, error) {
  341. if target.Items != nil {
  342. if target.Items.Schema != nil {
  343. t, err := expandSchema(*target.Items.Schema, parentRefs, resolver)
  344. if err != nil {
  345. return nil, err
  346. }
  347. *target.Items.Schema = *t
  348. }
  349. for i := range target.Items.Schemas {
  350. t, err := expandSchema(target.Items.Schemas[i], parentRefs, resolver)
  351. if err != nil {
  352. return nil, err
  353. }
  354. target.Items.Schemas[i] = *t
  355. }
  356. }
  357. return &target, nil
  358. }
  359. func expandSchema(target Schema, parentRefs []string, resolver *schemaLoader) (schema *Schema, err error) {
  360. defer func() {
  361. schema = &target
  362. }()
  363. if target.Ref.String() == "" && target.Ref.IsRoot() {
  364. target = *resolver.root.(*Schema)
  365. return
  366. }
  367. // t is the new expanded schema
  368. var t *Schema
  369. for target.Ref.String() != "" {
  370. // var newTarget Schema
  371. pRefs := strings.Join(parentRefs, ",")
  372. pRefs += ","
  373. if strings.Contains(pRefs, target.Ref.String()+",") {
  374. err = nil
  375. return
  376. }
  377. if err = resolver.Resolve(&target.Ref, &t); err != nil {
  378. return
  379. }
  380. parentRefs = append(parentRefs, target.Ref.String())
  381. target = *t
  382. }
  383. if t, err = expandItems(target, parentRefs, resolver); err != nil {
  384. return
  385. }
  386. target = *t
  387. for i := range target.AllOf {
  388. if t, err = expandSchema(target.AllOf[i], parentRefs, resolver); err != nil {
  389. return
  390. }
  391. target.AllOf[i] = *t
  392. }
  393. for i := range target.AnyOf {
  394. if t, err = expandSchema(target.AnyOf[i], parentRefs, resolver); err != nil {
  395. return
  396. }
  397. target.AnyOf[i] = *t
  398. }
  399. for i := range target.OneOf {
  400. if t, err = expandSchema(target.OneOf[i], parentRefs, resolver); err != nil {
  401. return
  402. }
  403. target.OneOf[i] = *t
  404. }
  405. if target.Not != nil {
  406. if t, err = expandSchema(*target.Not, parentRefs, resolver); err != nil {
  407. return
  408. }
  409. *target.Not = *t
  410. }
  411. for k, _ := range target.Properties {
  412. if t, err = expandSchema(target.Properties[k], parentRefs, resolver); err != nil {
  413. return
  414. }
  415. target.Properties[k] = *t
  416. }
  417. if target.AdditionalProperties != nil && target.AdditionalProperties.Schema != nil {
  418. if t, err = expandSchema(*target.AdditionalProperties.Schema, parentRefs, resolver); err != nil {
  419. return
  420. }
  421. *target.AdditionalProperties.Schema = *t
  422. }
  423. for k, _ := range target.PatternProperties {
  424. if t, err = expandSchema(target.PatternProperties[k], parentRefs, resolver); err != nil {
  425. return
  426. }
  427. target.PatternProperties[k] = *t
  428. }
  429. for k, _ := range target.Dependencies {
  430. if target.Dependencies[k].Schema != nil {
  431. if t, err = expandSchema(*target.Dependencies[k].Schema, parentRefs, resolver); err != nil {
  432. return
  433. }
  434. *target.Dependencies[k].Schema = *t
  435. }
  436. }
  437. if target.AdditionalItems != nil && target.AdditionalItems.Schema != nil {
  438. if t, err = expandSchema(*target.AdditionalItems.Schema, parentRefs, resolver); err != nil {
  439. return
  440. }
  441. *target.AdditionalItems.Schema = *t
  442. }
  443. for k, _ := range target.Definitions {
  444. if t, err = expandSchema(target.Definitions[k], parentRefs, resolver); err != nil {
  445. return
  446. }
  447. target.Definitions[k] = *t
  448. }
  449. return
  450. }
  451. func expandPathItem(pathItem *PathItem, resolver *schemaLoader) error {
  452. if pathItem == nil {
  453. return nil
  454. }
  455. if pathItem.Ref.String() != "" {
  456. if err := resolver.Resolve(&pathItem.Ref, &pathItem); err != nil {
  457. return err
  458. }
  459. }
  460. for idx := range pathItem.Parameters {
  461. if err := expandParameter(&(pathItem.Parameters[idx]), resolver); err != nil {
  462. return err
  463. }
  464. }
  465. if err := expandOperation(pathItem.Get, resolver); err != nil {
  466. return err
  467. }
  468. if err := expandOperation(pathItem.Head, resolver); err != nil {
  469. return err
  470. }
  471. if err := expandOperation(pathItem.Options, resolver); err != nil {
  472. return err
  473. }
  474. if err := expandOperation(pathItem.Put, resolver); err != nil {
  475. return err
  476. }
  477. if err := expandOperation(pathItem.Post, resolver); err != nil {
  478. return err
  479. }
  480. if err := expandOperation(pathItem.Patch, resolver); err != nil {
  481. return err
  482. }
  483. if err := expandOperation(pathItem.Delete, resolver); err != nil {
  484. return err
  485. }
  486. return nil
  487. }
  488. func expandOperation(op *Operation, resolver *schemaLoader) error {
  489. if op == nil {
  490. return nil
  491. }
  492. for i, param := range op.Parameters {
  493. if err := expandParameter(&param, resolver); err != nil {
  494. return err
  495. }
  496. op.Parameters[i] = param
  497. }
  498. if op.Responses != nil {
  499. responses := op.Responses
  500. if err := expandResponse(responses.Default, resolver); err != nil {
  501. return err
  502. }
  503. for code, response := range responses.StatusCodeResponses {
  504. if err := expandResponse(&response, resolver); err != nil {
  505. return err
  506. }
  507. responses.StatusCodeResponses[code] = response
  508. }
  509. }
  510. return nil
  511. }
  512. func expandResponse(response *Response, resolver *schemaLoader) error {
  513. if response == nil {
  514. return nil
  515. }
  516. if response.Ref.String() != "" {
  517. if err := resolver.Resolve(&response.Ref, response); err != nil {
  518. return err
  519. }
  520. }
  521. if response.Schema != nil {
  522. parentRefs := []string{response.Schema.Ref.String()}
  523. if err := resolver.Resolve(&response.Schema.Ref, &response.Schema); err != nil {
  524. return err
  525. }
  526. if s, err := expandSchema(*response.Schema, parentRefs, resolver); err != nil {
  527. return err
  528. } else {
  529. *response.Schema = *s
  530. }
  531. }
  532. return nil
  533. }
  534. func expandParameter(parameter *Parameter, resolver *schemaLoader) error {
  535. if parameter == nil {
  536. return nil
  537. }
  538. if parameter.Ref.String() != "" {
  539. if err := resolver.Resolve(&parameter.Ref, parameter); err != nil {
  540. return err
  541. }
  542. }
  543. if parameter.Schema != nil {
  544. parentRefs := []string{parameter.Schema.Ref.String()}
  545. if err := resolver.Resolve(&parameter.Schema.Ref, &parameter.Schema); err != nil {
  546. return err
  547. }
  548. if s, err := expandSchema(*parameter.Schema, parentRefs, resolver); err != nil {
  549. return err
  550. } else {
  551. *parameter.Schema = *s
  552. }
  553. }
  554. return nil
  555. }