|
9 | 9 | "net/http" |
10 | 10 | "net/url" |
11 | 11 | "path" |
| 12 | + "reflect" |
12 | 13 | "strings" |
13 | 14 |
|
14 | 15 | "github.com/ghodss/yaml" |
@@ -247,24 +248,72 @@ func isSingleRefElement(ref string) bool { |
247 | 248 | return !strings.Contains(ref, "#") |
248 | 249 | } |
249 | 250 |
|
250 | | -func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref string, prefix string, path *url.URL) ( |
251 | | - components *Components, |
252 | | - id string, |
| 251 | +func (swaggerLoader *SwaggerLoader) resolveComponent(swagger *Swagger, ref string, path *url.URL) ( |
| 252 | + cursor interface{}, |
253 | 253 | componentPath *url.URL, |
254 | 254 | err error, |
255 | 255 | ) { |
256 | 256 | if swagger, ref, componentPath, err = swaggerLoader.resolveRefSwagger(swagger, ref, path); err != nil { |
257 | | - return nil, "", nil, err |
| 257 | + return nil, nil, err |
258 | 258 | } |
259 | | - if !strings.HasPrefix(ref, prefix) { |
260 | | - err := fmt.Errorf("expected prefix '%s' in URI '%s'", prefix, ref) |
261 | | - return nil, "", nil, err |
| 259 | + |
| 260 | + parsedURL, err := url.Parse(ref) |
| 261 | + if err != nil { |
| 262 | + return nil, nil, fmt.Errorf("Can't parse reference: '%s': %v", ref, parsedURL) |
262 | 263 | } |
263 | | - id = ref[len(prefix):] |
264 | | - if strings.IndexByte(id, '/') >= 0 { |
265 | | - return nil, "", nil, failedToResolveRefFragmentPart(ref, id) |
| 264 | + fragment := parsedURL.Fragment |
| 265 | + if !strings.HasPrefix(fragment, "/") { |
| 266 | + err := fmt.Errorf("expected fragment prefix '#/' in URI '%s'", ref) |
| 267 | + return nil, nil, err |
| 268 | + } |
| 269 | + |
| 270 | + cursor = swagger |
| 271 | + for _, pathPart := range strings.Split(fragment[1:], "/") { |
| 272 | + |
| 273 | + pathPart = strings.Replace(pathPart, "~1", "/", -1) |
| 274 | + pathPart = strings.Replace(pathPart, "~0", "~", -1) |
| 275 | + |
| 276 | + cursor, err = drillIntoSwaggerField(cursor, pathPart) |
| 277 | + if err != nil { |
| 278 | + return nil, nil, fmt.Errorf("Failed to resolve '%s' in fragment in URI: '%s': %v", ref, pathPart, err.Error()) |
| 279 | + } |
| 280 | + if cursor == nil { |
| 281 | + return nil, nil, failedToResolveRefFragmentPart(ref, pathPart) |
| 282 | + } |
| 283 | + } |
| 284 | + |
| 285 | + return cursor, componentPath, nil |
| 286 | +} |
| 287 | + |
| 288 | +func drillIntoSwaggerField(cursor interface{}, fieldName string) (interface{}, error) { |
| 289 | + val := reflect.Indirect(reflect.ValueOf(cursor)) |
| 290 | + |
| 291 | + switch val.Kind() { |
| 292 | + case reflect.Map: |
| 293 | + elementValue := val.MapIndex(reflect.ValueOf(fieldName)) |
| 294 | + if !elementValue.IsValid() { |
| 295 | + return nil, fmt.Errorf("Map key not found: %v", fieldName) |
| 296 | + } |
| 297 | + return elementValue.Interface(), nil |
| 298 | + |
| 299 | + case reflect.Struct: |
| 300 | + for i := 0; i < val.NumField(); i++ { |
| 301 | + field := val.Type().Field(i) |
| 302 | + tagValue := field.Tag.Get("yaml") |
| 303 | + yamlKey := strings.Split(tagValue, ",")[0] |
| 304 | + if yamlKey == fieldName { |
| 305 | + return val.Field(i).Interface(), nil |
| 306 | + } |
| 307 | + } |
| 308 | + // if cursor if a "ref wrapper" struct (e.g. RequestBodyRef), try digging into its Value field |
| 309 | + _, ok := val.Type().FieldByName("Value") |
| 310 | + if ok { |
| 311 | + return drillIntoSwaggerField(val.FieldByName("Value").Interface(), fieldName) // recurse into .Value |
| 312 | + } |
| 313 | + // give up |
| 314 | + return nil, fmt.Errorf("Struct field not found: %v", fieldName) |
266 | 315 | } |
267 | | - return &swagger.Components, id, componentPath, nil |
| 316 | + return nil, fmt.Errorf("Not a map or struct") |
268 | 317 | } |
269 | 318 |
|
270 | 319 | func (swaggerLoader *SwaggerLoader) resolveRefSwagger(swagger *Swagger, ref string, path *url.URL) (*Swagger, string, *url.URL, error) { |
@@ -313,16 +362,12 @@ func (swaggerLoader *SwaggerLoader) resolveHeaderRef(swagger *Swagger, component |
313 | 362 |
|
314 | 363 | component.Value = &header |
315 | 364 | } else { |
316 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path) |
| 365 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path) |
317 | 366 | if err != nil { |
318 | 367 | return err |
319 | 368 | } |
320 | | - definitions := components.Headers |
321 | | - if definitions == nil { |
322 | | - return failedToResolveRefFragment(ref) |
323 | | - } |
324 | | - resolved := definitions[id] |
325 | | - if resolved == nil { |
| 369 | + resolved, ok := untypedResolved.(*HeaderRef) |
| 370 | + if !ok { |
326 | 371 | return failedToResolveRefFragment(ref) |
327 | 372 | } |
328 | 373 | if err := swaggerLoader.resolveHeaderRef(swagger, resolved, componentPath); err != nil { |
@@ -362,17 +407,13 @@ func (swaggerLoader *SwaggerLoader) resolveParameterRef(swagger *Swagger, compon |
362 | 407 | } |
363 | 408 | component.Value = ¶m |
364 | 409 | } else { |
365 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, documentPath) |
| 410 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath) |
366 | 411 | if err != nil { |
367 | 412 | return err |
368 | 413 | } |
369 | | - definitions := components.Parameters |
370 | | - if definitions == nil { |
371 | | - return failedToResolveRefFragmentPart(ref, "parameters") |
372 | | - } |
373 | | - resolved := definitions[id] |
374 | | - if resolved == nil { |
375 | | - return failedToResolveRefFragmentPart(ref, id) |
| 414 | + resolved, ok := untypedResolved.(*ParameterRef) |
| 415 | + if !ok { |
| 416 | + return failedToResolveRefFragment(ref) |
376 | 417 | } |
377 | 418 | if err := swaggerLoader.resolveParameterRef(swagger, resolved, componentPath); err != nil { |
378 | 419 | return err |
@@ -427,17 +468,13 @@ func (swaggerLoader *SwaggerLoader) resolveRequestBodyRef(swagger *Swagger, comp |
427 | 468 |
|
428 | 469 | component.Value = &requestBody |
429 | 470 | } else { |
430 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path) |
| 471 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path) |
431 | 472 | if err != nil { |
432 | 473 | return err |
433 | 474 | } |
434 | | - definitions := components.RequestBodies |
435 | | - if definitions == nil { |
436 | | - return failedToResolveRefFragmentPart(ref, "requestBodies") |
437 | | - } |
438 | | - resolved := definitions[id] |
439 | | - if resolved == nil { |
440 | | - return failedToResolveRefFragmentPart(ref, id) |
| 475 | + resolved, ok := untypedResolved.(*RequestBodyRef) |
| 476 | + if !ok { |
| 477 | + return failedToResolveRefFragment(ref) |
441 | 478 | } |
442 | 479 | if err = swaggerLoader.resolveRequestBodyRef(swagger, resolved, componentPath); err != nil { |
443 | 480 | return err |
@@ -486,17 +523,13 @@ func (swaggerLoader *SwaggerLoader) resolveResponseRef(swagger *Swagger, compone |
486 | 523 |
|
487 | 524 | component.Value = &resp |
488 | 525 | } else { |
489 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, documentPath) |
| 526 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath) |
490 | 527 | if err != nil { |
491 | 528 | return err |
492 | 529 | } |
493 | | - definitions := components.Responses |
494 | | - if definitions == nil { |
495 | | - return failedToResolveRefFragmentPart(ref, "responses") |
496 | | - } |
497 | | - resolved := definitions[id] |
498 | | - if resolved == nil { |
499 | | - return failedToResolveRefFragmentPart(ref, id) |
| 530 | + resolved, ok := untypedResolved.(*ResponseRef) |
| 531 | + if !ok { |
| 532 | + return failedToResolveRefFragment(ref) |
500 | 533 | } |
501 | 534 | if err := swaggerLoader.resolveResponseRef(swagger, resolved, componentPath); err != nil { |
502 | 535 | return err |
@@ -562,17 +595,14 @@ func (swaggerLoader *SwaggerLoader) resolveSchemaRef(swagger *Swagger, component |
562 | 595 | } |
563 | 596 | component.Value = &schema |
564 | 597 | } else { |
565 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, documentPath) |
| 598 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, documentPath) |
566 | 599 | if err != nil { |
567 | 600 | return err |
568 | 601 | } |
569 | | - definitions := components.Schemas |
570 | | - if definitions == nil { |
571 | | - return failedToResolveRefFragmentPart(ref, "schemas") |
572 | | - } |
573 | | - resolved := definitions[id] |
574 | | - if resolved == nil { |
575 | | - return failedToResolveRefFragmentPart(ref, id) |
| 602 | + |
| 603 | + resolved, ok := untypedResolved.(*SchemaRef) |
| 604 | + if !ok { |
| 605 | + return failedToResolveRefFragment(ref) |
576 | 606 | } |
577 | 607 | if err := swaggerLoader.resolveSchemaRef(swagger, resolved, componentPath); err != nil { |
578 | 608 | return err |
@@ -650,17 +680,13 @@ func (swaggerLoader *SwaggerLoader) resolveSecuritySchemeRef(swagger *Swagger, c |
650 | 680 |
|
651 | 681 | component.Value = &scheme |
652 | 682 | } else { |
653 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path) |
| 683 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path) |
654 | 684 | if err != nil { |
655 | 685 | return err |
656 | 686 | } |
657 | | - definitions := components.SecuritySchemes |
658 | | - if definitions == nil { |
659 | | - return failedToResolveRefFragmentPart(ref, "securitySchemes") |
660 | | - } |
661 | | - resolved := definitions[id] |
662 | | - if resolved == nil { |
663 | | - return failedToResolveRefFragmentPart(ref, id) |
| 687 | + resolved, ok := untypedResolved.(*SecuritySchemeRef) |
| 688 | + if !ok { |
| 689 | + return failedToResolveRefFragment(ref) |
664 | 690 | } |
665 | 691 | if err := swaggerLoader.resolveSecuritySchemeRef(swagger, resolved, componentPath); err != nil { |
666 | 692 | return err |
@@ -689,17 +715,13 @@ func (swaggerLoader *SwaggerLoader) resolveExampleRef(swagger *Swagger, componen |
689 | 715 |
|
690 | 716 | component.Value = &example |
691 | 717 | } else { |
692 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path) |
| 718 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path) |
693 | 719 | if err != nil { |
694 | 720 | return err |
695 | 721 | } |
696 | | - definitions := components.Examples |
697 | | - if definitions == nil { |
698 | | - return failedToResolveRefFragmentPart(ref, "examples") |
699 | | - } |
700 | | - resolved := definitions[id] |
701 | | - if resolved == nil { |
702 | | - return failedToResolveRefFragmentPart(ref, id) |
| 722 | + resolved, ok := untypedResolved.(*ExampleRef) |
| 723 | + if !ok { |
| 724 | + return failedToResolveRefFragment(ref) |
703 | 725 | } |
704 | 726 | if err := swaggerLoader.resolveExampleRef(swagger, resolved, componentPath); err != nil { |
705 | 727 | return err |
@@ -728,17 +750,13 @@ func (swaggerLoader *SwaggerLoader) resolveLinkRef(swagger *Swagger, component * |
728 | 750 |
|
729 | 751 | component.Value = &link |
730 | 752 | } else { |
731 | | - components, id, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, prefix, path) |
| 753 | + untypedResolved, componentPath, err := swaggerLoader.resolveComponent(swagger, ref, path) |
732 | 754 | if err != nil { |
733 | 755 | return err |
734 | 756 | } |
735 | | - definitions := components.Links |
736 | | - if definitions == nil { |
737 | | - return failedToResolveRefFragmentPart(ref, "links") |
738 | | - } |
739 | | - resolved := definitions[id] |
740 | | - if resolved == nil { |
741 | | - return failedToResolveRefFragmentPart(ref, id) |
| 757 | + resolved, ok := untypedResolved.(*LinkRef) |
| 758 | + if !ok { |
| 759 | + return failedToResolveRefFragment(ref) |
742 | 760 | } |
743 | 761 | if err := swaggerLoader.resolveLinkRef(swagger, resolved, componentPath); err != nil { |
744 | 762 | return err |
|
0 commit comments