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 15package spec 16 17import ( 18 "encoding/json" 19 "io/ioutil" 20 "log" 21 "net/http" 22 "net/http/httptest" 23 "os" 24 "path/filepath" 25 "regexp" 26 "runtime" 27 "strings" 28 "testing" 29 30 "github.com/go-openapi/jsonpointer" 31 "github.com/go-openapi/swag" 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34) 35 36var specs = filepath.Join("fixtures", "specs") 37 38var ( 39 rex = regexp.MustCompile(`"\$ref":\s*"(.+)"`) 40) 41 42func jsonDoc(path string) (json.RawMessage, error) { 43 data, err := swag.LoadFromFileOrHTTP(path) 44 if err != nil { 45 return nil, err 46 } 47 return json.RawMessage(data), nil 48} 49 50// tests that paths are normalized correctly 51func TestNormalizePaths(t *testing.T) { 52 type testNormalizePathsTestCases []struct { 53 refPath string 54 base string 55 expOutput string 56 } 57 testCases := func() testNormalizePathsTestCases { 58 testCases := testNormalizePathsTestCases{ 59 { 60 // http basePath, absolute refPath 61 refPath: "http://www.anotherexample.com/another/base/path/swagger.json#/definitions/Pet", 62 base: "http://www.example.com/base/path/swagger.json", 63 expOutput: "http://www.anotherexample.com/another/base/path/swagger.json#/definitions/Pet", 64 }, 65 { 66 // http basePath, relative refPath 67 refPath: "another/base/path/swagger.json#/definitions/Pet", 68 base: "http://www.example.com/base/path/swagger.json", 69 expOutput: "http://www.example.com/base/path/another/base/path/swagger.json#/definitions/Pet", 70 }, 71 } 72 if runtime.GOOS == "windows" { 73 testCases = append(testCases, testNormalizePathsTestCases{ 74 { 75 // file basePath, absolute refPath, no fragment 76 refPath: `C:\another\base\path.json`, 77 base: `C:\base\path.json`, 78 expOutput: `C:\another\base\path.json`, 79 }, 80 { 81 // file basePath, absolute refPath 82 refPath: `C:\another\base\path.json#/definitions/Pet`, 83 base: `C:\base\path.json`, 84 expOutput: `C:\another\base\path.json#/definitions/Pet`, 85 }, 86 { 87 // file basePath, relative refPath 88 refPath: `another\base\path.json#/definitions/Pet`, 89 base: `C:\base\path.json`, 90 expOutput: `C:\base\another\base\path.json#/definitions/Pet`, 91 }, 92 }...) 93 return testCases 94 } 95 // linux case 96 testCases = append(testCases, testNormalizePathsTestCases{ 97 { 98 // file basePath, absolute refPath, no fragment 99 refPath: "/another/base/path.json", 100 base: "/base/path.json", 101 expOutput: "/another/base/path.json", 102 }, 103 { 104 // file basePath, absolute refPath 105 refPath: "/another/base/path.json#/definitions/Pet", 106 base: "/base/path.json", 107 expOutput: "/another/base/path.json#/definitions/Pet", 108 }, 109 { 110 // file basePath, relative refPath 111 refPath: "another/base/path.json#/definitions/Pet", 112 base: "/base/path.json", 113 expOutput: "/base/another/base/path.json#/definitions/Pet", 114 }, 115 }...) 116 return testCases 117 }() 118 119 for _, tcase := range testCases { 120 out := normalizePaths(tcase.refPath, tcase.base) 121 assert.Equal(t, tcase.expOutput, out) 122 } 123} 124 125func TestExpandsKnownRef(t *testing.T) { 126 schema := RefProperty("http://json-schema.org/draft-04/schema#") 127 if assert.NoError(t, ExpandSchema(schema, nil, nil)) { 128 assert.Equal(t, "Core schema meta-schema", schema.Description) 129 } 130} 131 132func TestExpandResponseSchema(t *testing.T) { 133 fp := "./fixtures/local_expansion/spec.json" 134 b, err := jsonDoc(fp) 135 if assert.NoError(t, err) { 136 var spec Swagger 137 if err := json.Unmarshal(b, &spec); assert.NoError(t, err) { 138 err := ExpandSpec(&spec, &ExpandOptions{RelativeBase: fp}) 139 if assert.NoError(t, err) { 140 sch := spec.Paths.Paths["/item"].Get.Responses.StatusCodeResponses[200].Schema 141 if assert.NotNil(t, sch) { 142 assert.Empty(t, sch.Ref.String()) 143 assert.Contains(t, sch.Type, "object") 144 assert.Len(t, sch.Properties, 2) 145 } 146 } 147 } 148 } 149} 150 151func TestSpecExpansion(t *testing.T) { 152 spec := new(Swagger) 153 154 err := ExpandSpec(spec, nil) 155 assert.NoError(t, err) 156 157 specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") 158 assert.NoError(t, err) 159 160 specPath, _ := absPath("fixtures/expansion/all-the-things.json") 161 opts := &ExpandOptions{ 162 RelativeBase: specPath, 163 } 164 165 spec = new(Swagger) 166 err = json.Unmarshal(specDoc, spec) 167 assert.NoError(t, err) 168 169 pet := spec.Definitions["pet"] 170 errorModel := spec.Definitions["errorModel"] 171 petResponse := spec.Responses["petResponse"] 172 petResponse.Schema = &pet 173 stringResponse := spec.Responses["stringResponse"] 174 tagParam := spec.Parameters["tag"] 175 idParam := spec.Parameters["idParam"] 176 177 err = ExpandSpec(spec, opts) 178 assert.NoError(t, err) 179 180 assert.Equal(t, tagParam, spec.Parameters["query"]) 181 assert.Equal(t, petResponse, spec.Responses["petResponse"]) 182 assert.Equal(t, petResponse, spec.Responses["anotherPet"]) 183 assert.Equal(t, pet, *spec.Responses["petResponse"].Schema) 184 assert.Equal(t, stringResponse, *spec.Paths.Paths["/"].Get.Responses.Default) 185 assert.Equal(t, petResponse, spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]) 186 assert.Equal(t, pet, *spec.Paths.Paths["/pets"].Get.Responses.StatusCodeResponses[200].Schema.Items.Schema) 187 assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Get.Responses.Default.Schema) 188 assert.Equal(t, pet, spec.Definitions["petInput"].AllOf[0]) 189 assert.Equal(t, spec.Definitions["petInput"], *spec.Paths.Paths["/pets"].Post.Parameters[0].Schema) 190 assert.Equal(t, petResponse, spec.Paths.Paths["/pets"].Post.Responses.StatusCodeResponses[200]) 191 assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Post.Responses.Default.Schema) 192 pi := spec.Paths.Paths["/pets/{id}"] 193 assert.Equal(t, idParam, pi.Get.Parameters[0]) 194 assert.Equal(t, petResponse, pi.Get.Responses.StatusCodeResponses[200]) 195 assert.Equal(t, errorModel, *pi.Get.Responses.Default.Schema) 196 assert.Equal(t, idParam, pi.Delete.Parameters[0]) 197 assert.Equal(t, errorModel, *pi.Delete.Responses.Default.Schema) 198} 199 200func TestResolveRef(t *testing.T) { 201 var root interface{} 202 err := json.Unmarshal([]byte(PetStore20), &root) 203 assert.NoError(t, err) 204 ref, err := NewRef("#/definitions/Category") 205 assert.NoError(t, err) 206 sch, err := ResolveRef(root, &ref) 207 assert.NoError(t, err) 208 b, _ := sch.MarshalJSON() 209 assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) 210 211 // WithBase variant 212 sch, err = ResolveRefWithBase(root, &ref, &ExpandOptions{ 213 RelativeBase: "/", 214 }) 215 assert.NoError(t, err) 216 b, _ = sch.MarshalJSON() 217 assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b)) 218} 219 220func TestResponseExpansion(t *testing.T) { 221 specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") 222 assert.NoError(t, err) 223 224 basePath, err := absPath("fixtures/expansion/all-the-things.json") 225 assert.NoError(t, err) 226 227 spec := new(Swagger) 228 err = json.Unmarshal(specDoc, spec) 229 assert.NoError(t, err) 230 231 resolver, err := defaultSchemaLoader(spec, nil, nil, nil) 232 assert.NoError(t, err) 233 234 resp := spec.Responses["anotherPet"] 235 expected := spec.Responses["petResponse"] 236 err = expandParameterOrResponse(&expected, resolver, basePath) 237 assert.NoError(t, err) 238 239 jazon, _ := json.MarshalIndent(expected, "", " ") 240 assert.JSONEq(t, `{ 241 "description": "pet response", 242 "schema": { 243 "required": [ 244 "id", 245 "name" 246 ], 247 "properties": { 248 "id": { 249 "type": "integer", 250 "format": "int64" 251 }, 252 "name": { 253 "type": "string" 254 }, 255 "tag": { 256 "type": "string" 257 } 258 } 259 } 260 }`, string(jazon)) 261 262 err = expandParameterOrResponse(&resp, resolver, basePath) 263 assert.NoError(t, err) 264 assert.Equal(t, expected, resp) 265 266 resp2 := spec.Paths.Paths["/"].Get.Responses.Default 267 expected = spec.Responses["stringResponse"] 268 269 err = expandParameterOrResponse(resp2, resolver, basePath) 270 assert.NoError(t, err) 271 assert.Equal(t, expected, *resp2) 272 273 // cascading ref 274 resp = spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200] 275 expected = spec.Responses["petResponse"] 276 jazon, _ = json.MarshalIndent(resp, "", " ") 277 assert.JSONEq(t, `{ 278 "$ref": "#/responses/anotherPet" 279 }`, string(jazon)) 280 281 err = expandParameterOrResponse(&resp, resolver, basePath) 282 assert.NoError(t, err) 283 // NOTE(fredbi): fixed this testcase in schema_loader.go#227 284 assert.Equal(t, expected, resp) 285} 286 287func TestResponseResolve(t *testing.T) { 288 specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") 289 assert.NoError(t, err) 290 291 spec := new(Swagger) 292 err = json.Unmarshal(specDoc, spec) 293 assert.NoError(t, err) 294 295 // Resolve with root version 296 resp := spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200] 297 resp2, err := ResolveResponse(spec, resp.Ref) 298 assert.NoError(t, err) 299 // resolve resolves the ref, but dos not expand 300 jazon, _ := json.MarshalIndent(resp2, "", " ") 301 assert.JSONEq(t, `{ 302 "$ref": "#/responses/petResponse" 303 }`, string(jazon)) 304} 305 306// test the exported version of ExpandResponse 307func TestExportedResponseExpansion(t *testing.T) { 308 specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") 309 if !assert.NoError(t, err) { 310 t.FailNow() 311 } 312 313 basePath, err := absPath("fixtures/expansion/all-the-things.json") 314 assert.NoError(t, err) 315 316 spec := new(Swagger) 317 err = json.Unmarshal(specDoc, spec) 318 assert.NoError(t, err) 319 320 resp := spec.Responses["anotherPet"] 321 expected := spec.Responses["petResponse"] 322 err = ExpandResponse(&expected, basePath) 323 assert.NoError(t, err) 324 325 err = ExpandResponse(&resp, basePath) 326 assert.NoError(t, err) 327 assert.Equal(t, expected, resp) 328 329 resp2 := spec.Paths.Paths["/"].Get.Responses.Default 330 expected = spec.Responses["stringResponse"] 331 332 err = ExpandResponse(resp2, basePath) 333 assert.NoError(t, err) 334 assert.Equal(t, expected, *resp2) 335 336 resp = spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200] 337 expected = spec.Responses["petResponse"] 338 339 err = ExpandResponse(&resp, basePath) 340 assert.NoError(t, err) 341 // NOTE(fredbi): fixed this testcase in schema_loader.go#227 342 assert.Equal(t, expected, resp) 343} 344 345func TestExpandResponseAndParamWithRoot(t *testing.T) { 346 specDoc, err := jsonDoc("fixtures/bugs/1614/gitea.json") 347 if !assert.NoError(t, err) { 348 t.FailNow() 349 return 350 } 351 var spec Swagger 352 _ = json.Unmarshal(specDoc, &spec) 353 354 // check responses with $ref 355 resp := spec.Paths.Paths["/admin/users"].Post.Responses.StatusCodeResponses[201] 356 err = ExpandResponseWithRoot(&resp, spec, nil) 357 assert.NoError(t, err) 358 jazon, _ := json.MarshalIndent(resp, "", " ") 359 m := rex.FindAllStringSubmatch(string(jazon), -1) 360 assert.Nil(t, m) 361 362 resp = spec.Paths.Paths["/admin/users"].Post.Responses.StatusCodeResponses[403] 363 err = ExpandResponseWithRoot(&resp, spec, nil) 364 assert.NoError(t, err) 365 jazon, _ = json.MarshalIndent(resp, "", " ") 366 m = rex.FindAllStringSubmatch(string(jazon), -1) 367 assert.Nil(t, m) 368 369 // check param with $ref 370 param := spec.Paths.Paths["/admin/users"].Post.Parameters[0] 371 err = ExpandParameterWithRoot(¶m, spec, nil) 372 assert.NoError(t, err) 373 jazon, _ = json.MarshalIndent(param, "", " ") 374 m = rex.FindAllStringSubmatch(string(jazon), -1) 375 assert.Nil(t, m) 376} 377 378func TestResolveParam(t *testing.T) { 379 specDoc, err := jsonDoc("fixtures/expansion/all-the-things.json") 380 if !assert.NoError(t, err) { 381 t.FailNow() 382 } 383 var spec Swagger 384 _ = json.Unmarshal(specDoc, &spec) 385 386 param := spec.Paths.Paths["/pets/{id}"].Get.Parameters[0] 387 par, err := ResolveParameter(spec, param.Ref) 388 assert.NoError(t, err) 389 jazon, _ := json.MarshalIndent(par, "", " ") 390 assert.JSONEq(t, `{ 391 "name": "id", 392 "in": "path", 393 "description": "ID of pet to fetch", 394 "required": true, 395 "type": "integer", 396 "format": "int64" 397 }`, string(jazon)) 398} 399 400func TestIssue3(t *testing.T) { 401 spec := new(Swagger) 402 specDoc, err := jsonDoc("fixtures/expansion/overflow.json") 403 assert.NoError(t, err) 404 405 specPath, _ := absPath("fixtures/expansion/overflow.json") 406 opts := &ExpandOptions{ 407 RelativeBase: specPath, 408 } 409 410 err = json.Unmarshal(specDoc, spec) 411 assert.NoError(t, err) 412 413 assert.NotPanics(t, func() { 414 err = ExpandSpec(spec, opts) 415 assert.NoError(t, err) 416 }, "Calling expand spec with circular refs, should not panic!") 417} 418 419func TestParameterExpansion(t *testing.T) { 420 paramDoc, err := jsonDoc("fixtures/expansion/params.json") 421 assert.NoError(t, err) 422 423 spec := new(Swagger) 424 err = json.Unmarshal(paramDoc, spec) 425 assert.NoError(t, err) 426 427 basePath, err := absPath("fixtures/expansion/params.json") 428 assert.NoError(t, err) 429 430 resolver, err := defaultSchemaLoader(spec, nil, nil, nil) 431 assert.NoError(t, err) 432 433 param := spec.Parameters["query"] 434 expected := spec.Parameters["tag"] 435 436 err = expandParameterOrResponse(¶m, resolver, basePath) 437 assert.NoError(t, err) 438 assert.Equal(t, expected, param) 439 440 param = spec.Paths.Paths["/cars/{id}"].Parameters[0] 441 expected = spec.Parameters["id"] 442 443 err = expandParameterOrResponse(¶m, resolver, basePath) 444 assert.NoError(t, err) 445 assert.Equal(t, expected, param) 446} 447 448func TestExportedParameterExpansion(t *testing.T) { 449 paramDoc, err := jsonDoc("fixtures/expansion/params.json") 450 assert.NoError(t, err) 451 452 spec := new(Swagger) 453 err = json.Unmarshal(paramDoc, spec) 454 assert.NoError(t, err) 455 456 basePath, err := absPath("fixtures/expansion/params.json") 457 assert.NoError(t, err) 458 459 param := spec.Parameters["query"] 460 expected := spec.Parameters["tag"] 461 462 err = ExpandParameter(¶m, basePath) 463 assert.NoError(t, err) 464 assert.Equal(t, expected, param) 465 466 param = spec.Paths.Paths["/cars/{id}"].Parameters[0] 467 expected = spec.Parameters["id"] 468 469 err = ExpandParameter(¶m, basePath) 470 assert.NoError(t, err) 471 assert.Equal(t, expected, param) 472} 473 474func TestCircularRefsExpansion(t *testing.T) { 475 carsDoc, err := jsonDoc("fixtures/expansion/circularRefs.json") 476 assert.NoError(t, err) 477 478 basePath, _ := absPath("fixtures/expansion/circularRefs.json") 479 480 spec := new(Swagger) 481 err = json.Unmarshal(carsDoc, spec) 482 assert.NoError(t, err) 483 484 resolver, err := defaultSchemaLoader(spec, &ExpandOptions{RelativeBase: basePath}, nil, nil) 485 assert.NoError(t, err) 486 schema := spec.Definitions["car"] 487 488 assert.NotPanics(t, func() { 489 _, err := expandSchema(schema, []string{"#/definitions/car"}, resolver, basePath) 490 assert.NoError(t, err) 491 }, "Calling expand schema with circular refs, should not panic!") 492} 493 494func TestCircularSpec2Expansion(t *testing.T) { 495 // TODO: assert repeatable results (see commented section below) 496 497 fixturePath := filepath.Join("fixtures", "expansion", "circular-minimal.json") 498 jazon := expandThisOrDieTrying(t, fixturePath) 499 assert.NotEmpty(t, jazon) 500 // assert stripped $ref in result 501 assert.NotContainsf(t, jazon, "circular-minimal.json#/", 502 "expected %s to be expanded with stripped circular $ref", fixturePath) 503 504 fixturePath = "fixtures/expansion/circularSpec2.json" 505 jazon = expandThisOrDieTrying(t, fixturePath) 506 assert.NotEmpty(t, jazon) 507 assert.NotContainsf(t, jazon, "circularSpec.json#/", 508 "expected %s to be expanded with stripped circular $ref", fixturePath) 509 510 /* 511 512 At the moment, the result of expanding circular references is not stable, 513 when several cycles have intersections: 514 the spec structure is randomly walked through and mutating as expansion is carried out. 515 detected cycles in $ref are not necessarily the shortest matches. 516 517 This may result in different, functionally correct expanded spec (e.g. with same validations) 518 519 for i := 0; i < 1; i++ { 520 bbb := expandThisOrDieTrying(t, fixturePath) 521 t.Log(bbb) 522 if !assert.JSONEqf(t, jazon, bbb, "on iteration %d, we should have stable expanded spec", i) { 523 t.FailNow() 524 return 525 } 526 } 527 */ 528} 529 530func Test_MoreCircular(t *testing.T) { 531 // Additional testcase for circular $ref (from go-openapi/validate): 532 // - $ref with file = current file 533 // - circular is located in remote file 534 // 535 // There are 4 variants to run: 536 // - with/without $ref with local file (so its not really remote) 537 // - with circular in a schema in #/responses 538 // - with circular in a schema in #/parameters 539 540 fixturePath := "fixtures/more_circulars/spec.json" 541 jazon := expandThisOrDieTrying(t, fixturePath) 542 m := rex.FindAllStringSubmatch(jazon, -1) 543 if assert.NotNil(t, m) { 544 for _, matched := range m { 545 subMatch := matched[1] 546 assert.True(t, strings.HasPrefix(subMatch, "item.json#/item"), 547 "expected $ref to be relative, got: %s", matched[0]) 548 } 549 } 550 551 fixturePath = "fixtures/more_circulars/spec2.json" 552 jazon = expandThisOrDieTrying(t, fixturePath) 553 m = rex.FindAllStringSubmatch(jazon, -1) 554 if assert.NotNil(t, m) { 555 for _, matched := range m { 556 subMatch := matched[1] 557 assert.True(t, strings.HasPrefix(subMatch, "item2.json#/item"), 558 "expected $ref to be relative, got: %s", matched[0]) 559 } 560 } 561 562 fixturePath = "fixtures/more_circulars/spec3.json" 563 jazon = expandThisOrDieTrying(t, fixturePath) 564 m = rex.FindAllStringSubmatch(jazon, -1) 565 if assert.NotNil(t, m) { 566 for _, matched := range m { 567 subMatch := matched[1] 568 assert.True(t, strings.HasPrefix(subMatch, "item.json#/item"), 569 "expected $ref to be relative, got: %s", matched[0]) 570 } 571 } 572 573 fixturePath = "fixtures/more_circulars/spec4.json" 574 jazon = expandThisOrDieTrying(t, fixturePath) 575 m = rex.FindAllStringSubmatch(jazon, -1) 576 if assert.NotNil(t, m) { 577 for _, matched := range m { 578 subMatch := matched[1] 579 assert.True(t, strings.HasPrefix(subMatch, "item4.json#/item"), 580 "expected $ref to be relative, got: %s", matched[0]) 581 } 582 } 583} 584 585func Test_Issue957(t *testing.T) { 586 fixturePath := "fixtures/bugs/957/fixture-957.json" 587 jazon := expandThisOrDieTrying(t, fixturePath) 588 if assert.NotEmpty(t, jazon) { 589 assert.NotContainsf(t, jazon, "fixture-957.json#/", 590 "expected %s to be expanded with stripped circular $ref", fixturePath) 591 m := rex.FindAllStringSubmatch(jazon, -1) 592 if assert.NotNil(t, m) { 593 for _, matched := range m { 594 subMatch := matched[1] 595 assert.True(t, strings.HasPrefix(subMatch, "#/definitions/"), 596 "expected $ref to be inlined, got: %s", matched[0]) 597 } 598 } 599 //t.Log(jazon) 600 } 601} 602 603func Test_Bitbucket(t *testing.T) { 604 // Additional testcase for circular $ref (from bitbucket api) 605 606 fixturePath := "fixtures/more_circulars/bitbucket.json" 607 jazon := expandThisOrDieTrying(t, fixturePath) 608 m := rex.FindAllStringSubmatch(jazon, -1) 609 if assert.NotNil(t, m) { 610 for _, matched := range m { 611 subMatch := matched[1] 612 assert.True(t, strings.HasPrefix(subMatch, "#/definitions/"), 613 "expected $ref to be inlined, got: %s", matched[0]) 614 } 615 } 616} 617 618func Test_ExpandJSONSchemaDraft4(t *testing.T) { 619 fixturePath := filepath.Join("schemas", "jsonschema-draft-04.json") 620 jazon := expandThisSchemaOrDieTrying(t, fixturePath) 621 // assert all $ref maches "$ref": "http://json-schema.org/draft-04/something" 622 m := rex.FindAllStringSubmatch(jazon, -1) 623 if assert.NotNil(t, m) { 624 for _, matched := range m { 625 subMatch := matched[1] 626 assert.True(t, strings.HasPrefix(subMatch, "http://json-schema.org/draft-04/"), 627 "expected $ref to be remote, got: %s", matched[0]) 628 } 629 } 630} 631 632func Test_ExpandSwaggerSchema(t *testing.T) { 633 fixturePath := filepath.Join("schemas", "v2", "schema.json") 634 jazon := expandThisSchemaOrDieTrying(t, fixturePath) 635 // assert all $ref maches "$ref": "#/definitions/something" 636 m := rex.FindAllStringSubmatch(jazon, -1) 637 if assert.NotNil(t, m) { 638 for _, matched := range m { 639 // matched := m[0] 640 subMatch := matched[1] 641 assert.True(t, strings.HasPrefix(subMatch, "#/definitions/"), 642 "expected $ref to be inlined, got: %s", matched[0]) 643 } 644 } 645} 646 647func expandThisSchemaOrDieTrying(t *testing.T, fixturePath string) string { 648 doc, err := jsonDoc(fixturePath) 649 require.NoError(t, err) 650 651 specPath, _ := absPath(fixturePath) 652 653 opts := &ExpandOptions{ 654 RelativeBase: specPath, 655 } 656 657 sch := new(Schema) 658 err = json.Unmarshal(doc, sch) 659 require.NoError(t, err) 660 661 require.NotPanics(t, func() { 662 err = ExpandSchemaWithBasePath(sch, nil, opts) 663 assert.NoError(t, err) 664 }, "Calling expand schema circular refs, should not panic!") 665 666 bbb, _ := json.MarshalIndent(sch, "", " ") 667 return string(bbb) 668} 669 670func expandThisOrDieTrying(t *testing.T, fixturePath string) string { 671 doc, err := jsonDoc(fixturePath) 672 if !assert.NoError(t, err) { 673 t.FailNow() 674 return "" 675 } 676 677 specPath, _ := absPath(fixturePath) 678 679 opts := &ExpandOptions{ 680 RelativeBase: specPath, 681 } 682 683 spec := new(Swagger) 684 err = json.Unmarshal(doc, spec) 685 if !assert.NoError(t, err) { 686 t.FailNow() 687 return "" 688 } 689 690 assert.NotPanics(t, func() { 691 err = ExpandSpec(spec, opts) 692 assert.NoError(t, err) 693 }, "Calling expand spec with circular refs, should not panic!") 694 695 bbb, _ := json.MarshalIndent(spec, "", " ") 696 return string(bbb) 697} 698 699func TestContinueOnErrorExpansion(t *testing.T) { 700 defer log.SetOutput(os.Stdout) 701 log.SetOutput(ioutil.Discard) 702 703 missingRefDoc, err := jsonDoc("fixtures/expansion/missingRef.json") 704 assert.NoError(t, err) 705 706 specPath, _ := absPath("fixtures/expansion/missingRef.json") 707 708 testCase := struct { 709 Input *Swagger `json:"input"` 710 Expected *Swagger `json:"expected"` 711 }{} 712 err = json.Unmarshal(missingRefDoc, &testCase) 713 assert.NoError(t, err) 714 715 opts := &ExpandOptions{ 716 ContinueOnError: true, 717 RelativeBase: specPath, 718 } 719 err = ExpandSpec(testCase.Input, opts) 720 assert.NoError(t, err) 721 // b, _ := testCase.Input.MarshalJSON() 722 // log.Printf(string(b)) 723 assert.Equal(t, testCase.Input, testCase.Expected, "Should continue expanding spec when a definition can't be found.") 724 725 doc, err := jsonDoc("fixtures/expansion/missingItemRef.json") 726 spec := new(Swagger) 727 err = json.Unmarshal(doc, spec) 728 assert.NoError(t, err) 729 730 assert.NotPanics(t, func() { 731 err = ExpandSpec(spec, opts) 732 assert.NoError(t, err) 733 }, "Array of missing refs should not cause a panic, and continue to expand spec.") 734} 735 736func TestIssue415(t *testing.T) { 737 doc, err := jsonDoc("fixtures/expansion/clickmeter.json") 738 assert.NoError(t, err) 739 740 specPath, _ := absPath("fixtures/expansion/clickmeter.json") 741 742 opts := &ExpandOptions{ 743 RelativeBase: specPath, 744 } 745 746 spec := new(Swagger) 747 err = json.Unmarshal(doc, spec) 748 assert.NoError(t, err) 749 750 assert.NotPanics(t, func() { 751 err = ExpandSpec(spec, opts) 752 assert.NoError(t, err) 753 }, "Calling expand spec with response schemas that have circular refs, should not panic!") 754} 755 756func TestCircularSpecExpansion(t *testing.T) { 757 doc, err := jsonDoc("fixtures/expansion/circularSpec.json") 758 assert.NoError(t, err) 759 760 specPath, _ := absPath("fixtures/expansion/circularSpec.json") 761 762 opts := &ExpandOptions{ 763 RelativeBase: specPath, 764 } 765 766 spec := new(Swagger) 767 err = json.Unmarshal(doc, spec) 768 assert.NoError(t, err) 769 770 assert.NotPanics(t, func() { 771 err = ExpandSpec(spec, opts) 772 assert.NoError(t, err) 773 }, "Calling expand spec with circular refs, should not panic!") 774} 775 776func TestItemsExpansion(t *testing.T) { 777 carsDoc, err := jsonDoc("fixtures/expansion/schemas2.json") 778 assert.NoError(t, err) 779 780 basePath, _ := absPath("fixtures/expansion/schemas2.json") 781 782 spec := new(Swagger) 783 err = json.Unmarshal(carsDoc, spec) 784 assert.NoError(t, err) 785 786 resolver, err := defaultSchemaLoader(spec, nil, nil, nil) 787 assert.NoError(t, err) 788 789 schema := spec.Definitions["car"] 790 oldBrand := schema.Properties["brand"] 791 assert.NotEmpty(t, oldBrand.Items.Schema.Ref.String()) 792 assert.NotEqual(t, spec.Definitions["brand"], oldBrand) 793 794 _, err = expandSchema(schema, []string{"#/definitions/car"}, resolver, basePath) 795 assert.NoError(t, err) 796 797 newBrand := schema.Properties["brand"] 798 assert.Empty(t, newBrand.Items.Schema.Ref.String()) 799 assert.Equal(t, spec.Definitions["brand"], *newBrand.Items.Schema) 800 801 schema = spec.Definitions["truck"] 802 assert.NotEmpty(t, schema.Items.Schema.Ref.String()) 803 804 s, err := expandSchema(schema, []string{"#/definitions/truck"}, resolver, basePath) 805 schema = *s 806 assert.NoError(t, err) 807 assert.Empty(t, schema.Items.Schema.Ref.String()) 808 assert.Equal(t, spec.Definitions["car"], *schema.Items.Schema) 809 810 sch := new(Schema) 811 _, err = expandSchema(*sch, []string{""}, resolver, basePath) 812 assert.NoError(t, err) 813 814 schema = spec.Definitions["batch"] 815 s, err = expandSchema(schema, []string{"#/definitions/batch"}, resolver, basePath) 816 schema = *s 817 assert.NoError(t, err) 818 assert.Empty(t, schema.Items.Schema.Items.Schema.Ref.String()) 819 assert.Equal(t, *schema.Items.Schema.Items.Schema, spec.Definitions["brand"]) 820 821 schema = spec.Definitions["batch2"] 822 s, err = expandSchema(schema, []string{"#/definitions/batch2"}, resolver, basePath) 823 schema = *s 824 assert.NoError(t, err) 825 assert.Empty(t, schema.Items.Schemas[0].Items.Schema.Ref.String()) 826 assert.Empty(t, schema.Items.Schemas[1].Items.Schema.Ref.String()) 827 assert.Equal(t, *schema.Items.Schemas[0].Items.Schema, spec.Definitions["brand"]) 828 assert.Equal(t, *schema.Items.Schemas[1].Items.Schema, spec.Definitions["tag"]) 829 830 schema = spec.Definitions["allofBoth"] 831 s, err = expandSchema(schema, []string{"#/definitions/allofBoth"}, resolver, basePath) 832 schema = *s 833 assert.NoError(t, err) 834 assert.Empty(t, schema.AllOf[0].Items.Schema.Ref.String()) 835 assert.Empty(t, schema.AllOf[1].Items.Schema.Ref.String()) 836 assert.Equal(t, *schema.AllOf[0].Items.Schema, spec.Definitions["brand"]) 837 assert.Equal(t, *schema.AllOf[1].Items.Schema, spec.Definitions["tag"]) 838 839 schema = spec.Definitions["anyofBoth"] 840 s, err = expandSchema(schema, []string{"#/definitions/anyofBoth"}, resolver, basePath) 841 schema = *s 842 assert.NoError(t, err) 843 assert.Empty(t, schema.AnyOf[0].Items.Schema.Ref.String()) 844 assert.Empty(t, schema.AnyOf[1].Items.Schema.Ref.String()) 845 assert.Equal(t, *schema.AnyOf[0].Items.Schema, spec.Definitions["brand"]) 846 assert.Equal(t, *schema.AnyOf[1].Items.Schema, spec.Definitions["tag"]) 847 848 schema = spec.Definitions["oneofBoth"] 849 s, err = expandSchema(schema, []string{"#/definitions/oneofBoth"}, resolver, basePath) 850 schema = *s 851 assert.NoError(t, err) 852 assert.Empty(t, schema.OneOf[0].Items.Schema.Ref.String()) 853 assert.Empty(t, schema.OneOf[1].Items.Schema.Ref.String()) 854 assert.Equal(t, *schema.OneOf[0].Items.Schema, spec.Definitions["brand"]) 855 assert.Equal(t, *schema.OneOf[1].Items.Schema, spec.Definitions["tag"]) 856 857 schema = spec.Definitions["notSomething"] 858 s, err = expandSchema(schema, []string{"#/definitions/notSomething"}, resolver, basePath) 859 schema = *s 860 assert.NoError(t, err) 861 assert.Empty(t, schema.Not.Items.Schema.Ref.String()) 862 assert.Equal(t, *schema.Not.Items.Schema, spec.Definitions["tag"]) 863 864 schema = spec.Definitions["withAdditional"] 865 s, err = expandSchema(schema, []string{"#/definitions/withAdditional"}, resolver, basePath) 866 schema = *s 867 assert.NoError(t, err) 868 assert.Empty(t, schema.AdditionalProperties.Schema.Items.Schema.Ref.String()) 869 assert.Equal(t, *schema.AdditionalProperties.Schema.Items.Schema, spec.Definitions["tag"]) 870 871 schema = spec.Definitions["withAdditionalItems"] 872 s, err = expandSchema(schema, []string{"#/definitions/withAdditionalItems"}, resolver, basePath) 873 schema = *s 874 assert.NoError(t, err) 875 assert.Empty(t, schema.AdditionalItems.Schema.Items.Schema.Ref.String()) 876 assert.Equal(t, *schema.AdditionalItems.Schema.Items.Schema, spec.Definitions["tag"]) 877 878 schema = spec.Definitions["withPattern"] 879 s, err = expandSchema(schema, []string{"#/definitions/withPattern"}, resolver, basePath) 880 schema = *s 881 assert.NoError(t, err) 882 prop := schema.PatternProperties["^x-ab"] 883 assert.Empty(t, prop.Items.Schema.Ref.String()) 884 assert.Equal(t, *prop.Items.Schema, spec.Definitions["tag"]) 885 886 schema = spec.Definitions["deps"] 887 s, err = expandSchema(schema, []string{"#/definitions/deps"}, resolver, basePath) 888 schema = *s 889 assert.NoError(t, err) 890 prop2 := schema.Dependencies["something"] 891 assert.Empty(t, prop2.Schema.Items.Schema.Ref.String()) 892 assert.Equal(t, *prop2.Schema.Items.Schema, spec.Definitions["tag"]) 893 894 schema = spec.Definitions["defined"] 895 s, err = expandSchema(schema, []string{"#/definitions/defined"}, resolver, basePath) 896 schema = *s 897 assert.NoError(t, err) 898 prop = schema.Definitions["something"] 899 assert.Empty(t, prop.Items.Schema.Ref.String()) 900 assert.Equal(t, *prop.Items.Schema, spec.Definitions["tag"]) 901} 902 903func TestSchemaExpansion(t *testing.T) { 904 carsDoc, err := jsonDoc("fixtures/expansion/schemas1.json") 905 assert.NoError(t, err) 906 907 basePath, _ := absPath("fixtures/expansion/schemas1.json") 908 909 spec := new(Swagger) 910 err = json.Unmarshal(carsDoc, spec) 911 assert.NoError(t, err) 912 913 resolver, err := defaultSchemaLoader(spec, nil, nil, nil) 914 assert.NoError(t, err) 915 916 schema := spec.Definitions["car"] 917 oldBrand := schema.Properties["brand"] 918 assert.NotEmpty(t, oldBrand.Ref.String()) 919 assert.NotEqual(t, spec.Definitions["brand"], oldBrand) 920 921 s, err := expandSchema(schema, []string{"#/definitions/car"}, resolver, basePath) 922 schema = *s 923 assert.NoError(t, err) 924 925 newBrand := schema.Properties["brand"] 926 assert.Empty(t, newBrand.Ref.String()) 927 assert.Equal(t, spec.Definitions["brand"], newBrand) 928 929 schema = spec.Definitions["truck"] 930 assert.NotEmpty(t, schema.Ref.String()) 931 932 s, err = expandSchema(schema, []string{"#/definitions/truck"}, resolver, basePath) 933 schema = *s 934 assert.NoError(t, err) 935 assert.Empty(t, schema.Ref.String()) 936 assert.Equal(t, spec.Definitions["car"], schema) 937 938 sch := new(Schema) 939 _, err = expandSchema(*sch, []string{""}, resolver, basePath) 940 assert.NoError(t, err) 941 942 schema = spec.Definitions["batch"] 943 s, err = expandSchema(schema, []string{"#/definitions/batch"}, resolver, basePath) 944 schema = *s 945 assert.NoError(t, err) 946 assert.Empty(t, schema.Items.Schema.Ref.String()) 947 assert.Equal(t, *schema.Items.Schema, spec.Definitions["brand"]) 948 949 schema = spec.Definitions["batch2"] 950 s, err = expandSchema(schema, []string{"#/definitions/batch2"}, resolver, basePath) 951 schema = *s 952 assert.NoError(t, err) 953 assert.Empty(t, schema.Items.Schemas[0].Ref.String()) 954 assert.Empty(t, schema.Items.Schemas[1].Ref.String()) 955 assert.Equal(t, schema.Items.Schemas[0], spec.Definitions["brand"]) 956 assert.Equal(t, schema.Items.Schemas[1], spec.Definitions["tag"]) 957 958 schema = spec.Definitions["allofBoth"] 959 s, err = expandSchema(schema, []string{"#/definitions/allofBoth"}, resolver, basePath) 960 schema = *s 961 assert.NoError(t, err) 962 assert.Empty(t, schema.AllOf[0].Ref.String()) 963 assert.Empty(t, schema.AllOf[1].Ref.String()) 964 assert.Equal(t, schema.AllOf[0], spec.Definitions["brand"]) 965 assert.Equal(t, schema.AllOf[1], spec.Definitions["tag"]) 966 967 schema = spec.Definitions["anyofBoth"] 968 s, err = expandSchema(schema, []string{"#/definitions/anyofBoth"}, resolver, basePath) 969 schema = *s 970 assert.NoError(t, err) 971 assert.Empty(t, schema.AnyOf[0].Ref.String()) 972 assert.Empty(t, schema.AnyOf[1].Ref.String()) 973 assert.Equal(t, schema.AnyOf[0], spec.Definitions["brand"]) 974 assert.Equal(t, schema.AnyOf[1], spec.Definitions["tag"]) 975 976 schema = spec.Definitions["oneofBoth"] 977 s, err = expandSchema(schema, []string{"#/definitions/oneofBoth"}, resolver, basePath) 978 schema = *s 979 assert.NoError(t, err) 980 assert.Empty(t, schema.OneOf[0].Ref.String()) 981 assert.Empty(t, schema.OneOf[1].Ref.String()) 982 assert.Equal(t, schema.OneOf[0], spec.Definitions["brand"]) 983 assert.Equal(t, schema.OneOf[1], spec.Definitions["tag"]) 984 985 schema = spec.Definitions["notSomething"] 986 s, err = expandSchema(schema, []string{"#/definitions/notSomething"}, resolver, basePath) 987 schema = *s 988 assert.NoError(t, err) 989 assert.Empty(t, schema.Not.Ref.String()) 990 assert.Equal(t, *schema.Not, spec.Definitions["tag"]) 991 992 schema = spec.Definitions["withAdditional"] 993 s, err = expandSchema(schema, []string{"#/definitions/withAdditional"}, resolver, basePath) 994 schema = *s 995 assert.NoError(t, err) 996 assert.Empty(t, schema.AdditionalProperties.Schema.Ref.String()) 997 assert.Equal(t, *schema.AdditionalProperties.Schema, spec.Definitions["tag"]) 998 999 schema = spec.Definitions["withAdditionalItems"] 1000 s, err = expandSchema(schema, []string{"#/definitions/withAdditionalItems"}, resolver, basePath) 1001 schema = *s 1002 assert.NoError(t, err) 1003 assert.Empty(t, schema.AdditionalItems.Schema.Ref.String()) 1004 assert.Equal(t, *schema.AdditionalItems.Schema, spec.Definitions["tag"]) 1005 1006 schema = spec.Definitions["withPattern"] 1007 s, err = expandSchema(schema, []string{"#/definitions/withPattern"}, resolver, basePath) 1008 schema = *s 1009 assert.NoError(t, err) 1010 prop := schema.PatternProperties["^x-ab"] 1011 assert.Empty(t, prop.Ref.String()) 1012 assert.Equal(t, prop, spec.Definitions["tag"]) 1013 1014 schema = spec.Definitions["deps"] 1015 s, err = expandSchema(schema, []string{"#/definitions/deps"}, resolver, basePath) 1016 schema = *s 1017 assert.NoError(t, err) 1018 prop2 := schema.Dependencies["something"] 1019 assert.Empty(t, prop2.Schema.Ref.String()) 1020 assert.Equal(t, *prop2.Schema, spec.Definitions["tag"]) 1021 1022 schema = spec.Definitions["defined"] 1023 s, err = expandSchema(schema, []string{"#/definitions/defined"}, resolver, basePath) 1024 schema = *s 1025 assert.NoError(t, err) 1026 prop = schema.Definitions["something"] 1027 assert.Empty(t, prop.Ref.String()) 1028 assert.Equal(t, prop, spec.Definitions["tag"]) 1029 1030} 1031 1032func TestDefaultResolutionCache(t *testing.T) { 1033 1034 cache := initResolutionCache() 1035 1036 sch, ok := cache.Get("not there") 1037 assert.False(t, ok) 1038 assert.Nil(t, sch) 1039 1040 sch, ok = cache.Get("http://swagger.io/v2/schema.json") 1041 assert.True(t, ok) 1042 assert.Equal(t, swaggerSchema, sch) 1043 1044 sch, ok = cache.Get("http://json-schema.org/draft-04/schema") 1045 assert.True(t, ok) 1046 assert.Equal(t, jsonSchema, sch) 1047 1048 cache.Set("something", "here") 1049 sch, ok = cache.Get("something") 1050 assert.True(t, ok) 1051 assert.Equal(t, "here", sch) 1052} 1053 1054func TestRelativeBaseURI(t *testing.T) { 1055 server := httptest.NewServer(http.FileServer(http.Dir("fixtures/remote"))) 1056 defer server.Close() 1057 1058 spec := new(Swagger) 1059 // resolver, err := defaultSchemaLoader(spec, nil, nil,nil) 1060 // assert.NoError(t, err) 1061 1062 err := ExpandSpec(spec, nil) 1063 assert.NoError(t, err) 1064 1065 specDoc, err := jsonDoc("fixtures/remote/all-the-things.json") 1066 assert.NoError(t, err) 1067 1068 opts := &ExpandOptions{ 1069 RelativeBase: server.URL + "/all-the-things.json", 1070 } 1071 1072 spec = new(Swagger) 1073 err = json.Unmarshal(specDoc, spec) 1074 assert.NoError(t, err) 1075 1076 pet := spec.Definitions["pet"] 1077 errorModel := spec.Definitions["errorModel"] 1078 petResponse := spec.Responses["petResponse"] 1079 petResponse.Schema = &pet 1080 stringResponse := spec.Responses["stringResponse"] 1081 tagParam := spec.Parameters["tag"] 1082 idParam := spec.Parameters["idParam"] 1083 1084 anotherPet := spec.Responses["anotherPet"] 1085 anotherPet.Ref = MustCreateRef(server.URL + "/" + anotherPet.Ref.String()) 1086 err = ExpandResponse(&anotherPet, opts.RelativeBase) 1087 assert.NoError(t, err) 1088 spec.Responses["anotherPet"] = anotherPet 1089 1090 circularA := spec.Responses["circularA"] 1091 circularA.Ref = MustCreateRef(server.URL + "/" + circularA.Ref.String()) 1092 err = ExpandResponse(&circularA, opts.RelativeBase) 1093 assert.NoError(t, err) 1094 spec.Responses["circularA"] = circularA 1095 1096 err = ExpandSpec(spec, opts) 1097 assert.NoError(t, err) 1098 1099 assert.Equal(t, tagParam, spec.Parameters["query"]) 1100 assert.Equal(t, petResponse, spec.Responses["petResponse"]) 1101 // ICI 1102 assert.Equal(t, petResponse, spec.Responses["anotherPet"]) 1103 // ICI 1104 assert.Equal(t, pet, *spec.Responses["petResponse"].Schema) 1105 assert.Equal(t, stringResponse, *spec.Paths.Paths["/"].Get.Responses.Default) 1106 assert.Equal(t, petResponse, spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]) 1107 assert.Equal(t, pet, *spec.Paths.Paths["/pets"].Get.Responses.StatusCodeResponses[200].Schema.Items.Schema) 1108 assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Get.Responses.Default.Schema) 1109 assert.Equal(t, pet, spec.Definitions["petInput"].AllOf[0]) 1110 assert.Equal(t, spec.Definitions["petInput"], *spec.Paths.Paths["/pets"].Post.Parameters[0].Schema) 1111 assert.Equal(t, petResponse, spec.Paths.Paths["/pets"].Post.Responses.StatusCodeResponses[200]) 1112 assert.Equal(t, errorModel, *spec.Paths.Paths["/pets"].Post.Responses.Default.Schema) 1113 pi := spec.Paths.Paths["/pets/{id}"] 1114 assert.Equal(t, idParam, pi.Get.Parameters[0]) 1115 assert.Equal(t, petResponse, pi.Get.Responses.StatusCodeResponses[200]) 1116 assert.Equal(t, errorModel, *pi.Get.Responses.Default.Schema) 1117 assert.Equal(t, idParam, pi.Delete.Parameters[0]) 1118 assert.Equal(t, errorModel, *pi.Delete.Responses.Default.Schema) 1119} 1120 1121func resolutionContextServer() *httptest.Server { 1122 var servedAt string 1123 server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { 1124 // fmt.Println("got a request for", req.URL.String()) 1125 if req.URL.Path == "/resolution.json" { 1126 1127 b, _ := ioutil.ReadFile(filepath.Join(specs, "resolution.json")) 1128 var ctnt map[string]interface{} 1129 _ = json.Unmarshal(b, &ctnt) 1130 ctnt["id"] = servedAt 1131 1132 rw.Header().Set("Content-Type", "application/json") 1133 rw.WriteHeader(200) 1134 bb, _ := json.Marshal(ctnt) 1135 _, _ = rw.Write(bb) 1136 return 1137 } 1138 if req.URL.Path == "/resolution2.json" { 1139 b, _ := ioutil.ReadFile(filepath.Join(specs, "resolution2.json")) 1140 var ctnt map[string]interface{} 1141 _ = json.Unmarshal(b, &ctnt) 1142 ctnt["id"] = servedAt 1143 1144 rw.Header().Set("Content-Type", "application/json") 1145 rw.WriteHeader(200) 1146 bb, _ := json.Marshal(ctnt) 1147 _, _ = rw.Write(bb) 1148 return 1149 } 1150 1151 if req.URL.Path == "/boolProp.json" { 1152 rw.Header().Set("Content-Type", "application/json") 1153 rw.WriteHeader(200) 1154 b, _ := json.Marshal(map[string]interface{}{ 1155 "type": "boolean", 1156 }) 1157 _, _ = rw.Write(b) 1158 return 1159 } 1160 1161 if req.URL.Path == "/deeper/stringProp.json" { 1162 rw.Header().Set("Content-Type", "application/json") 1163 rw.WriteHeader(200) 1164 b, _ := json.Marshal(map[string]interface{}{ 1165 "type": "string", 1166 }) 1167 _, _ = rw.Write(b) 1168 return 1169 } 1170 1171 if req.URL.Path == "/deeper/arrayProp.json" { 1172 rw.Header().Set("Content-Type", "application/json") 1173 rw.WriteHeader(200) 1174 b, _ := json.Marshal(map[string]interface{}{ 1175 "type": "array", 1176 "items": map[string]interface{}{ 1177 "type": "file", 1178 }, 1179 }) 1180 _, _ = rw.Write(b) 1181 return 1182 } 1183 1184 rw.WriteHeader(http.StatusNotFound) 1185 })) 1186 servedAt = server.URL 1187 return server 1188} 1189 1190func TestResolveRemoteRef_RootSame(t *testing.T) { 1191 fileserver := http.FileServer(http.Dir(specs)) 1192 server := httptest.NewServer(fileserver) 1193 defer server.Close() 1194 1195 rootDoc := new(Swagger) 1196 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1197 // the filename doesn't matter because ref will eventually point to refed.json 1198 specBase, _ := absPath(filepath.Join(specs, "anyotherfile.json")) 1199 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1200 var result0 Swagger 1201 ref0, _ := NewRef(server.URL + "/refed.json#") 1202 resolver0, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1203 if assert.NoError(t, resolver0.Resolve(&ref0, &result0, "")) { 1204 assertSpecs(t, result0, *rootDoc) 1205 } 1206 1207 var result1 Swagger 1208 ref1, _ := NewRef("./refed.json") 1209 resolver1, _ := defaultSchemaLoader(rootDoc, &ExpandOptions{ 1210 RelativeBase: specBase, 1211 }, nil, nil) 1212 if assert.NoError(t, resolver1.Resolve(&ref1, &result1, specBase)) { 1213 assertSpecs(t, result1, *rootDoc) 1214 } 1215 } 1216} 1217 1218func TestResolveRemoteRef_FromFragment(t *testing.T) { 1219 fileserver := http.FileServer(http.Dir(specs)) 1220 server := httptest.NewServer(fileserver) 1221 defer server.Close() 1222 1223 rootDoc := new(Swagger) 1224 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1225 1226 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1227 var tgt Schema 1228 ref, err := NewRef(server.URL + "/refed.json#/definitions/pet") 1229 if assert.NoError(t, err) { 1230 resolver := &schemaLoader{root: rootDoc, cache: initResolutionCache(), loadDoc: jsonDoc} 1231 if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { 1232 assert.Equal(t, []string{"id", "name"}, tgt.Required) 1233 } 1234 } 1235 } 1236} 1237 1238func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) { 1239 fileserver := http.FileServer(http.Dir(specs)) 1240 server := httptest.NewServer(fileserver) 1241 defer server.Close() 1242 1243 rootDoc := new(Swagger) 1244 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1245 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1246 var tgt Schema 1247 ref, err := NewRef(server.URL + "/refed.json#/definitions/NotThere") 1248 if assert.NoError(t, err) { 1249 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1250 assert.Error(t, resolver.Resolve(&ref, &tgt, "")) 1251 } 1252 } 1253} 1254 1255func TestResolveRemoteRef_WithResolutionContext(t *testing.T) { 1256 server := resolutionContextServer() 1257 defer server.Close() 1258 1259 var tgt Schema 1260 ref, err := NewRef(server.URL + "/resolution.json#/definitions/bool") 1261 if assert.NoError(t, err) { 1262 tgt.Ref = ref 1263 ere := ExpandSchema(&tgt, nil, nil) 1264 assert.NoError(t, ere) 1265 assert.Equal(t, StringOrArray([]string{"boolean"}), tgt.Type) 1266 } 1267 1268} 1269 1270func TestResolveRemoteRef_WithNestedResolutionContext(t *testing.T) { 1271 server := resolutionContextServer() 1272 defer server.Close() 1273 1274 var tgt Schema 1275 ref, err := NewRef(server.URL + "/resolution.json#/items") 1276 if assert.NoError(t, err) { 1277 tgt.Ref = ref 1278 ere := ExpandSchema(&tgt, nil, nil) 1279 assert.NoError(t, ere) 1280 assert.Equal(t, StringOrArray([]string{"string"}), tgt.Items.Schema.Type) 1281 } 1282} 1283 1284/* This next test will have to wait until we do full $ID analysis for every subschema on every file that is referenced */ 1285/* For now, TestResolveRemoteRef_WithNestedResolutionContext replaces this next test */ 1286// func TestResolveRemoteRef_WithNestedResolutionContext_WithParentID(t *testing.T) { 1287// server := resolutionContextServer() 1288// defer server.Close() 1289 1290// var tgt Schema 1291// ref, err := NewRef(server.URL + "/resolution.json#/items/items") 1292// if assert.NoError(t, err) { 1293// tgt.Ref = ref 1294// ExpandSchema(&tgt, nil, nil) 1295// assert.Equal(t, StringOrArray([]string{"string"}), tgt.Type) 1296// } 1297// } 1298 1299func TestResolveRemoteRef_WithNestedResolutionContextWithFragment(t *testing.T) { 1300 server := resolutionContextServer() 1301 defer server.Close() 1302 1303 var tgt Schema 1304 ref, err := NewRef(server.URL + "/resolution2.json#/items") 1305 if assert.NoError(t, err) { 1306 tgt.Ref = ref 1307 ere := ExpandSchema(&tgt, nil, nil) 1308 assert.NoError(t, ere) 1309 assert.Equal(t, StringOrArray([]string{"file"}), tgt.Items.Schema.Type) 1310 } 1311 1312} 1313 1314/* This next test will have to wait until we do full $ID analysis for every subschema on every file that is referenced */ 1315/* For now, TestResolveRemoteRef_WithNestedResolutionContext replaces this next test */ 1316// func TestResolveRemoteRef_WithNestedResolutionContextWithFragment_WithParentID(t *testing.T) { 1317// server := resolutionContextServer() 1318// defer server.Close() 1319 1320// rootDoc := new(Swagger) 1321// b, err := ioutil.ReadFile("fixtures/specs/refed.json") 1322// if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1323// var tgt Schema 1324// ref, err := NewRef(server.URL + "/resolution2.json#/items/items") 1325// if assert.NoError(t, err) { 1326// resolver, _ := defaultSchemaLoader(rootDoc, nil, nil,nil) 1327// if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { 1328// assert.Equal(t, StringOrArray([]string{"file"}), tgt.Type) 1329// } 1330// } 1331// } 1332// } 1333 1334func TestResolveRemoteRef_ToParameter(t *testing.T) { 1335 fileserver := http.FileServer(http.Dir(specs)) 1336 server := httptest.NewServer(fileserver) 1337 defer server.Close() 1338 1339 rootDoc := new(Swagger) 1340 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1341 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1342 var tgt Parameter 1343 ref, err := NewRef(server.URL + "/refed.json#/parameters/idParam") 1344 if assert.NoError(t, err) { 1345 1346 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1347 if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { 1348 assert.Equal(t, "id", tgt.Name) 1349 assert.Equal(t, "path", tgt.In) 1350 assert.Equal(t, "ID of pet to fetch", tgt.Description) 1351 assert.True(t, tgt.Required) 1352 assert.Equal(t, "integer", tgt.Type) 1353 assert.Equal(t, "int64", tgt.Format) 1354 } 1355 } 1356 } 1357} 1358 1359func TestResolveRemoteRef_ToPathItem(t *testing.T) { 1360 fileserver := http.FileServer(http.Dir(specs)) 1361 server := httptest.NewServer(fileserver) 1362 defer server.Close() 1363 1364 rootDoc := new(Swagger) 1365 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1366 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1367 var tgt PathItem 1368 ref, err := NewRef(server.URL + "/refed.json#/paths/" + jsonpointer.Escape("/pets/{id}")) 1369 if assert.NoError(t, err) { 1370 1371 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1372 if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { 1373 assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) 1374 } 1375 } 1376 } 1377} 1378 1379func TestResolveRemoteRef_ToResponse(t *testing.T) { 1380 fileserver := http.FileServer(http.Dir(specs)) 1381 server := httptest.NewServer(fileserver) 1382 defer server.Close() 1383 1384 rootDoc := new(Swagger) 1385 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1386 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1387 var tgt Response 1388 ref, err := NewRef(server.URL + "/refed.json#/responses/petResponse") 1389 if assert.NoError(t, err) { 1390 1391 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1392 if assert.NoError(t, resolver.Resolve(&ref, &tgt, "")) { 1393 assert.Equal(t, rootDoc.Responses["petResponse"], tgt) 1394 } 1395 } 1396 } 1397} 1398 1399func TestResolveLocalRef_SameRoot(t *testing.T) { 1400 rootDoc := new(Swagger) 1401 _ = json.Unmarshal(PetStoreJSONMessage, rootDoc) 1402 1403 result := new(Swagger) 1404 ref, _ := NewRef("#") 1405 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1406 err := resolver.Resolve(&ref, result, "") 1407 if assert.NoError(t, err) { 1408 assert.Equal(t, rootDoc, result) 1409 } 1410} 1411 1412func TestResolveLocalRef_FromFragment(t *testing.T) { 1413 rootDoc := new(Swagger) 1414 _ = json.Unmarshal(PetStoreJSONMessage, rootDoc) 1415 1416 var tgt Schema 1417 ref, err := NewRef("#/definitions/Category") 1418 if assert.NoError(t, err) { 1419 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1420 err := resolver.Resolve(&ref, &tgt, "") 1421 if assert.NoError(t, err) { 1422 assert.Equal(t, "Category", tgt.ID) 1423 } 1424 } 1425} 1426 1427func TestResolveLocalRef_FromInvalidFragment(t *testing.T) { 1428 rootDoc := new(Swagger) 1429 _ = json.Unmarshal(PetStoreJSONMessage, rootDoc) 1430 1431 var tgt Schema 1432 ref, err := NewRef("#/definitions/NotThere") 1433 if assert.NoError(t, err) { 1434 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1435 err := resolver.Resolve(&ref, &tgt, "") 1436 assert.Error(t, err) 1437 } 1438} 1439 1440func TestResolveLocalRef_Parameter(t *testing.T) { 1441 rootDoc := new(Swagger) 1442 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1443 basePath, _ := absPath(filepath.Join(specs, "refed.json")) 1444 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1445 var tgt Parameter 1446 ref, err := NewRef("#/parameters/idParam") 1447 if assert.NoError(t, err) { 1448 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1449 if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { 1450 assert.Equal(t, "id", tgt.Name) 1451 assert.Equal(t, "path", tgt.In) 1452 assert.Equal(t, "ID of pet to fetch", tgt.Description) 1453 assert.True(t, tgt.Required) 1454 assert.Equal(t, "integer", tgt.Type) 1455 assert.Equal(t, "int64", tgt.Format) 1456 } 1457 } 1458 } 1459} 1460 1461func TestResolveLocalRef_PathItem(t *testing.T) { 1462 rootDoc := new(Swagger) 1463 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1464 basePath, _ := absPath(filepath.Join(specs, "refed.json")) 1465 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1466 var tgt PathItem 1467 ref, err := NewRef("#/paths/" + jsonpointer.Escape("/pets/{id}")) 1468 if assert.NoError(t, err) { 1469 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1470 if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { 1471 assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) 1472 } 1473 } 1474 } 1475} 1476 1477func TestResolveLocalRef_Response(t *testing.T) { 1478 rootDoc := new(Swagger) 1479 b, err := ioutil.ReadFile(filepath.Join(specs, "refed.json")) 1480 basePath, _ := absPath(filepath.Join(specs, "refed.json")) 1481 if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { 1482 var tgt Response 1483 ref, err := NewRef("#/responses/petResponse") 1484 if assert.NoError(t, err) { 1485 resolver, _ := defaultSchemaLoader(rootDoc, nil, nil, nil) 1486 if assert.NoError(t, resolver.Resolve(&ref, &tgt, basePath)) { 1487 assert.Equal(t, rootDoc.Responses["petResponse"], tgt) 1488 } 1489 } 1490 } 1491} 1492 1493func TestResolveForTransitiveRefs(t *testing.T) { 1494 var spec *Swagger 1495 rawSpec, err := ioutil.ReadFile(filepath.Join(specs, "todos.json")) 1496 assert.NoError(t, err) 1497 1498 basePath, err := absPath(filepath.Join(specs, "todos.json")) 1499 assert.NoError(t, err) 1500 1501 opts := &ExpandOptions{ 1502 RelativeBase: basePath, 1503 } 1504 1505 err = json.Unmarshal(rawSpec, &spec) 1506 assert.NoError(t, err) 1507 1508 err = ExpandSpec(spec, opts) 1509 assert.NoError(t, err) 1510} 1511 1512const ( 1513 withoutSchemaID = "removed" 1514 withSchemaID = "schema" 1515) 1516 1517func TestExpandSchemaWithRoot(t *testing.T) { 1518 root := new(Swagger) 1519 _ = json.Unmarshal(PetStoreJSONMessage, root) 1520 1521 // 1. remove ID from root definition 1522 origPet := root.Definitions["Pet"] 1523 newPet := origPet 1524 newPet.ID = "" 1525 root.Definitions["Pet"] = newPet 1526 expandRootWithID(t, root, withoutSchemaID) 1527 1528 // 2. put back ID in Pet definition 1529 // nested $ref should fail 1530 //Debug = true 1531 root.Definitions["Pet"] = origPet 1532 expandRootWithID(t, root, withSchemaID) 1533} 1534 1535func expandRootWithID(t *testing.T, root *Swagger, testcase string) { 1536 t.Logf("case: expanding $ref to schema without ID, with nested $ref with %s ID", testcase) 1537 sch := &Schema{ 1538 SchemaProps: SchemaProps{ 1539 Ref: MustCreateRef("#/definitions/newPet"), 1540 }, 1541 } 1542 err := ExpandSchema(sch, root, nil) 1543 if testcase == withSchemaID { 1544 assert.Errorf(t, err, "expected %s NOT to expand properly because of the ID in the parent schema", sch.Ref.String()) 1545 } else { 1546 assert.NoErrorf(t, err, "expected %s to expand properly", sch.Ref.String()) 1547 } 1548 if Debug { 1549 bbb, _ := json.MarshalIndent(sch, "", " ") 1550 t.Log(string(bbb)) 1551 } 1552 1553 t.Log("case: expanding $ref to schema without nested $ref") 1554 sch = &Schema{ 1555 SchemaProps: SchemaProps{ 1556 Ref: MustCreateRef("#/definitions/Category"), 1557 }, 1558 } 1559 err = ExpandSchema(sch, root, nil) 1560 assert.NoErrorf(t, err, "expected %s to expand properly", sch.Ref.String()) 1561 if Debug { 1562 bbb, _ := json.MarshalIndent(sch, "", " ") 1563 t.Log(string(bbb)) 1564 } 1565 t.Logf("case: expanding $ref to schema with %s ID and nested $ref", testcase) 1566 sch = &Schema{ 1567 SchemaProps: SchemaProps{ 1568 Ref: MustCreateRef("#/definitions/Pet"), 1569 }, 1570 } 1571 err = ExpandSchema(sch, root, nil) 1572 if testcase == withSchemaID { 1573 assert.Errorf(t, err, "expected %s NOT to expand properly because of the ID in the parent schema", sch.Ref.String()) 1574 } else { 1575 assert.NoErrorf(t, err, "expected %s to expand properly", sch.Ref.String()) 1576 } 1577 if Debug { 1578 bbb, _ := json.MarshalIndent(sch, "", " ") 1579 t.Log(string(bbb)) 1580 } 1581} 1582 1583const pathItemsFixture = "fixtures/expansion/pathItems.json" 1584 1585func TestExpandPathItem(t *testing.T) { 1586 spec := new(Swagger) 1587 specDoc, err := jsonDoc(pathItemsFixture) 1588 assert.NoError(t, err) 1589 _ = json.Unmarshal(specDoc, spec) 1590 specPath, _ := absPath(pathItemsFixture) 1591 1592 // ExpandSpec use case 1593 err = ExpandSpec(spec, &ExpandOptions{RelativeBase: specPath}) 1594 if !assert.NoError(t, err) { 1595 t.FailNow() 1596 } 1597 jazon, _ := json.MarshalIndent(spec, "", " ") 1598 assert.JSONEq(t, `{ 1599 "swagger": "2.0", 1600 "info": { 1601 "title": "PathItems refs", 1602 "version": "1.0" 1603 }, 1604 "paths": { 1605 "/todos": { 1606 "get": { 1607 "responses": { 1608 "200": { 1609 "description": "List Todos", 1610 "schema": { 1611 "type": "array", 1612 "items": { 1613 "type": "string" 1614 } 1615 } 1616 }, 1617 "404": { 1618 "description": "error" 1619 } 1620 } 1621 } 1622 } 1623 } 1624 }`, string(jazon)) 1625} 1626 1627func TestResolvePathItem(t *testing.T) { 1628 spec := new(Swagger) 1629 specDoc, err := jsonDoc(pathItemsFixture) 1630 assert.NoError(t, err) 1631 _ = json.Unmarshal(specDoc, spec) 1632 specPath, _ := absPath(pathItemsFixture) 1633 1634 // Resolve use case 1635 pth := spec.Paths.Paths["/todos"] 1636 pathItem, err := ResolvePathItem(spec, pth.Ref, &ExpandOptions{RelativeBase: specPath}) 1637 assert.NoError(t, err) 1638 jazon, _ := json.MarshalIndent(pathItem, "", " ") 1639 assert.JSONEq(t, `{ 1640 "get": { 1641 "responses": { 1642 "200": { 1643 "description": "List Todos", 1644 "schema": { 1645 "type": "array", 1646 "items": { 1647 "type": "string" 1648 } 1649 } 1650 }, 1651 "404": { 1652 "description": "error" 1653 } 1654 } 1655 } 1656 }`, string(jazon)) 1657} 1658 1659const extraRefFixture = "fixtures/expansion/extraRef.json" 1660 1661func TestExpandExtraItems(t *testing.T) { 1662 spec := new(Swagger) 1663 specDoc, err := jsonDoc(extraRefFixture) 1664 assert.NoError(t, err) 1665 _ = json.Unmarshal(specDoc, spec) 1666 specPath, _ := absPath(extraRefFixture) 1667 1668 // ExpandSpec use case: unsupported $refs are not expanded 1669 err = ExpandSpec(spec, &ExpandOptions{RelativeBase: specPath}) 1670 if !assert.NoError(t, err) { 1671 t.FailNow() 1672 } 1673 jazon, _ := json.MarshalIndent(spec, "", " ") 1674 assert.JSONEq(t, `{ 1675 "schemes": [ 1676 "http" 1677 ], 1678 "swagger": "2.0", 1679 "info": { 1680 "title": "Supported, but non Swagger 20 compliant $ref constructs", 1681 "version": "2.1.0" 1682 }, 1683 "host": "item.com", 1684 "basePath": "/extraRefs", 1685 "paths": { 1686 "/employees": { 1687 "get": { 1688 "summary": "List Employee Types", 1689 "operationId": "LIST-Employees", 1690 "parameters": [ 1691 { 1692 "description": "unsupported $ref in simple param", 1693 "type": "array", 1694 "items": { 1695 "$ref": "#/definitions/arrayType" 1696 }, 1697 "name": "myQueryParam", 1698 "in": "query" 1699 } 1700 ], 1701 "responses": { 1702 "200": { 1703 "description": "unsupported $ref in header", 1704 "schema": { 1705 "type": "string" 1706 }, 1707 "headers": { 1708 "X-header": { 1709 "type": "array", 1710 "items": { 1711 "$ref": "#/definitions/headerType" 1712 } 1713 } 1714 } 1715 } 1716 } 1717 } 1718 } 1719 }, 1720 "definitions": { 1721 "arrayType": { 1722 "type": "integer", 1723 "format": "int32" 1724 }, 1725 "headerType": { 1726 "type": "string", 1727 "format": "uuid" 1728 } 1729 } 1730 }`, string(jazon)) 1731} 1732 1733func TestResolveExtraItem(t *testing.T) { 1734 // go-openapi extra goodie: $ref in simple schema Items and Headers 1735 spec := new(Swagger) 1736 specDoc, err := jsonDoc(extraRefFixture) 1737 assert.NoError(t, err) 1738 _ = json.Unmarshal(specDoc, spec) 1739 specPath, _ := absPath(extraRefFixture) 1740 1741 // Resolve param Items use case: here we explicitly resolve the unsuppord case 1742 parm := spec.Paths.Paths["/employees"].Get.Parameters[0] 1743 parmItem, err := ResolveItems(spec, parm.Items.Ref, &ExpandOptions{RelativeBase: specPath}) 1744 assert.NoError(t, err) 1745 jazon, _ := json.MarshalIndent(parmItem, "", " ") 1746 assert.JSONEq(t, `{ 1747 "type": "integer", 1748 "format": "int32" 1749 }`, string(jazon)) 1750 1751 // Resolve header Items use case: here we explicitly resolve the unsuppord case 1752 hdr := spec.Paths.Paths["/employees"].Get.Responses.StatusCodeResponses[200].Headers["X-header"] 1753 hdrItem, err := ResolveItems(spec, hdr.Items.Ref, &ExpandOptions{RelativeBase: specPath}) 1754 assert.NoError(t, err) 1755 jazon, _ = json.MarshalIndent(hdrItem, "", " ") 1756 assert.JSONEq(t, `{ 1757 "type": "string", 1758 "format": "uuid" 1759 }`, string(jazon)) 1760} 1761 1762// PetStoreJSONMessage json raw message for Petstore20 1763var PetStoreJSONMessage = json.RawMessage([]byte(PetStore20)) 1764 1765// PetStore20 json doc for swagger 2.0 pet store 1766const PetStore20 = `{ 1767 "swagger": "2.0", 1768 "info": { 1769 "version": "1.0.0", 1770 "title": "Swagger Petstore", 1771 "contact": { 1772 "name": "Wordnik API Team", 1773 "url": "http://developer.wordnik.com" 1774 }, 1775 "license": { 1776 "name": "Creative Commons 4.0 International", 1777 "url": "http://creativecommons.org/licenses/by/4.0/" 1778 } 1779 }, 1780 "host": "petstore.swagger.wordnik.com", 1781 "basePath": "/api", 1782 "schemes": [ 1783 "http" 1784 ], 1785 "paths": { 1786 "/pets": { 1787 "get": { 1788 "security": [ 1789 { 1790 "basic": [] 1791 } 1792 ], 1793 "tags": [ "Pet Operations" ], 1794 "operationId": "getAllPets", 1795 "parameters": [ 1796 { 1797 "name": "status", 1798 "in": "query", 1799 "description": "The status to filter by", 1800 "type": "string" 1801 }, 1802 { 1803 "name": "limit", 1804 "in": "query", 1805 "description": "The maximum number of results to return", 1806 "type": "integer", 1807 "format": "int64" 1808 } 1809 ], 1810 "summary": "Finds all pets in the system", 1811 "responses": { 1812 "200": { 1813 "description": "Pet response", 1814 "schema": { 1815 "type": "array", 1816 "items": { 1817 "$ref": "#/definitions/Pet" 1818 } 1819 } 1820 }, 1821 "default": { 1822 "description": "Unexpected error", 1823 "schema": { 1824 "$ref": "#/definitions/Error" 1825 } 1826 } 1827 } 1828 }, 1829 "post": { 1830 "security": [ 1831 { 1832 "basic": [] 1833 } 1834 ], 1835 "tags": [ "Pet Operations" ], 1836 "operationId": "createPet", 1837 "summary": "Creates a new pet", 1838 "consumes": ["application/x-yaml"], 1839 "produces": ["application/x-yaml"], 1840 "parameters": [ 1841 { 1842 "name": "pet", 1843 "in": "body", 1844 "description": "The Pet to create", 1845 "required": true, 1846 "schema": { 1847 "$ref": "#/definitions/newPet" 1848 } 1849 } 1850 ], 1851 "responses": { 1852 "200": { 1853 "description": "Created Pet response", 1854 "schema": { 1855 "$ref": "#/definitions/Pet" 1856 } 1857 }, 1858 "default": { 1859 "description": "Unexpected error", 1860 "schema": { 1861 "$ref": "#/definitions/Error" 1862 } 1863 } 1864 } 1865 } 1866 }, 1867 "/pets/{id}": { 1868 "delete": { 1869 "security": [ 1870 { 1871 "apiKey": [] 1872 } 1873 ], 1874 "description": "Deletes the Pet by id", 1875 "operationId": "deletePet", 1876 "parameters": [ 1877 { 1878 "name": "id", 1879 "in": "path", 1880 "description": "ID of pet to delete", 1881 "required": true, 1882 "type": "integer", 1883 "format": "int64" 1884 } 1885 ], 1886 "responses": { 1887 "204": { 1888 "description": "pet deleted" 1889 }, 1890 "default": { 1891 "description": "unexpected error", 1892 "schema": { 1893 "$ref": "#/definitions/Error" 1894 } 1895 } 1896 } 1897 }, 1898 "get": { 1899 "tags": [ "Pet Operations" ], 1900 "operationId": "getPetById", 1901 "summary": "Finds the pet by id", 1902 "responses": { 1903 "200": { 1904 "description": "Pet response", 1905 "schema": { 1906 "$ref": "#/definitions/Pet" 1907 } 1908 }, 1909 "default": { 1910 "description": "Unexpected error", 1911 "schema": { 1912 "$ref": "#/definitions/Error" 1913 } 1914 } 1915 } 1916 }, 1917 "parameters": [ 1918 { 1919 "name": "id", 1920 "in": "path", 1921 "description": "ID of pet", 1922 "required": true, 1923 "type": "integer", 1924 "format": "int64" 1925 } 1926 ] 1927 } 1928 }, 1929 "definitions": { 1930 "Category": { 1931 "id": "Category", 1932 "properties": { 1933 "id": { 1934 "format": "int64", 1935 "type": "integer" 1936 }, 1937 "name": { 1938 "type": "string" 1939 } 1940 } 1941 }, 1942 "Pet": { 1943 "id": "Pet", 1944 "properties": { 1945 "category": { 1946 "$ref": "#/definitions/Category" 1947 }, 1948 "id": { 1949 "description": "unique identifier for the pet", 1950 "format": "int64", 1951 "maximum": 100.0, 1952 "minimum": 0.0, 1953 "type": "integer" 1954 }, 1955 "name": { 1956 "type": "string" 1957 }, 1958 "photoUrls": { 1959 "items": { 1960 "type": "string" 1961 }, 1962 "type": "array" 1963 }, 1964 "status": { 1965 "description": "pet status in the store", 1966 "enum": [ 1967 "available", 1968 "pending", 1969 "sold" 1970 ], 1971 "type": "string" 1972 }, 1973 "tags": { 1974 "items": { 1975 "$ref": "#/definitions/Tag" 1976 }, 1977 "type": "array" 1978 } 1979 }, 1980 "required": [ 1981 "id", 1982 "name" 1983 ] 1984 }, 1985 "newPet": { 1986 "anyOf": [ 1987 { 1988 "$ref": "#/definitions/Pet" 1989 }, 1990 { 1991 "required": [ 1992 "name" 1993 ] 1994 } 1995 ] 1996 }, 1997 "Tag": { 1998 "id": "Tag", 1999 "properties": { 2000 "id": { 2001 "format": "int64", 2002 "type": "integer" 2003 }, 2004 "name": { 2005 "type": "string" 2006 } 2007 } 2008 }, 2009 "Error": { 2010 "required": [ 2011 "code", 2012 "message" 2013 ], 2014 "properties": { 2015 "code": { 2016 "type": "integer", 2017 "format": "int32" 2018 }, 2019 "message": { 2020 "type": "string" 2021 } 2022 } 2023 } 2024 }, 2025 "consumes": [ 2026 "application/json", 2027 "application/xml" 2028 ], 2029 "produces": [ 2030 "application/json", 2031 "application/xml", 2032 "text/plain", 2033 "text/html" 2034 ], 2035 "securityDefinitions": { 2036 "basic": { 2037 "type": "basic" 2038 }, 2039 "apiKey": { 2040 "type": "apiKey", 2041 "in": "header", 2042 "name": "X-API-KEY" 2043 } 2044 } 2045} 2046` 2047