func (s *Spec) analyzeOperations(path string, pi *spec.PathItem) { // TODO: resolve refs here? op := pi if pi.Ref.String() != "" { key := slashpath.Join("/paths", jsonpointer.Escape(path)) s.references.addPathItemRef(key, pi) } s.analyzeOperation("GET", path, op.Get) s.analyzeOperation("PUT", path, op.Put) s.analyzeOperation("POST", path, op.Post) s.analyzeOperation("PATCH", path, op.Patch) s.analyzeOperation("DELETE", path, op.Delete) s.analyzeOperation("HEAD", path, op.Head) s.analyzeOperation("OPTIONS", path, op.Options) for i, param := range op.Parameters { refPref := slashpath.Join("/paths", jsonpointer.Escape(path), "parameters", strconv.Itoa(i)) if param.Ref.String() != "" { s.references.addParamRef(refPref, ¶m) } if param.Pattern != "" { s.patterns.addParameterPattern(refPref, param.Pattern) } if param.Items != nil { s.analyzeItems("items", param.Items, refPref, "parameter") } if param.Schema != nil { s.analyzeSchema("schema", *param.Schema, refPref) } } }
func (s *Spec) initialize() { for _, c := range s.spec.Consumes { s.consumes[c] = struct{}{} } for _, c := range s.spec.Produces { s.produces[c] = struct{}{} } for _, ss := range s.spec.Security { for k := range ss { s.authSchemes[k] = struct{}{} } } for path, pathItem := range s.AllPaths() { s.analyzeOperations(path, &pathItem) } for name, parameter := range s.spec.Parameters { refPref := slashpath.Join("/parameters", jsonpointer.Escape(name)) if parameter.Items != nil { s.analyzeItems("items", parameter.Items, refPref, "parameter") } if parameter.In == "body" && parameter.Schema != nil { s.analyzeSchema("schema", *parameter.Schema, refPref) } if parameter.Pattern != "" { s.patterns.addParameterPattern(refPref, parameter.Pattern) } } for name, response := range s.spec.Responses { refPref := slashpath.Join("/responses", jsonpointer.Escape(name)) for k, v := range response.Headers { hRefPref := slashpath.Join(refPref, "headers", k) if v.Items != nil { s.analyzeItems("items", v.Items, hRefPref, "header") } if v.Pattern != "" { s.patterns.addHeaderPattern(hRefPref, v.Pattern) } } if response.Schema != nil { s.analyzeSchema("schema", *response.Schema, refPref) } } for name, schema := range s.spec.Definitions { s.analyzeSchema(name, schema, "/definitions") } // TODO: after analyzing all things and flattening schemas etc // resolve all the collected references to their final representations // best put in a separate method because this could get expensive }
func (s *SpecValidator) validateReferencedDefinitions() *Result { // Each referenceable definition must have references. defs := s.spec.Spec().Definitions if len(defs) == 0 { return nil } expected := make(map[string]struct{}) for k := range defs { expected["#/definitions/"+jsonpointer.Escape(k)] = struct{}{} } for _, k := range s.analyzer.AllDefinitionReferences() { if _, ok := expected[k]; ok { delete(expected, k) } } if len(expected) == 0 { return nil } var result Result for k := range expected { result.AddErrors(errors.New(422, "definition %q is not used anywhere", k)) } return &result }
func (s *Spec) analyzeOperation(method, path string, op *spec.Operation) { if op == nil { return } for _, c := range op.Consumes { s.consumes[c] = struct{}{} } for _, c := range op.Produces { s.produces[c] = struct{}{} } for _, ss := range op.Security { for k := range ss { s.authSchemes[k] = struct{}{} } } if _, ok := s.operations[method]; !ok { s.operations[method] = make(map[string]*spec.Operation) } s.operations[method][path] = op prefix := slashpath.Join("/paths", jsonpointer.Escape(path), strings.ToLower(method)) for i, param := range op.Parameters { refPref := slashpath.Join(prefix, "parameters", strconv.Itoa(i)) if param.Ref.String() != "" { s.references.addParamRef(refPref, ¶m) } s.analyzeItems("items", param.Items, refPref) if param.In == "body" && param.Schema != nil { s.analyzeSchema("schema", *param.Schema, refPref) } } if op.Responses != nil { if op.Responses.Default != nil { refPref := slashpath.Join(prefix, "responses", "default") if op.Responses.Default.Ref.String() != "" { s.references.addResponseRef(refPref, op.Responses.Default) } for _, v := range op.Responses.Default.Headers { s.analyzeItems("items", v.Items, refPref) } if op.Responses.Default.Schema != nil { s.analyzeSchema("schema", *op.Responses.Default.Schema, refPref) } } for k, res := range op.Responses.StatusCodeResponses { refPref := slashpath.Join(prefix, "responses", strconv.Itoa(k)) if res.Ref.String() != "" { s.references.addResponseRef(refPref, &res) } for _, v := range res.Headers { s.analyzeItems("items", v.Items, refPref) } if res.Schema != nil { s.analyzeSchema("schema", *res.Schema, refPref) } } } }
func (s *Spec) analyzeSchema(name string, schema spec.Schema, prefix string) { refURI := slashpath.Join(prefix, jsonpointer.Escape(name)) schRef := SchemaRef{ Name: name, Schema: &schema, Ref: spec.MustCreateRef("#" + refURI), TopLevel: prefix == "/definitions", } s.allSchemas["#"+refURI] = schRef if schema.Ref.String() != "" { s.references.addSchemaRef(refURI, schRef) } if schema.Pattern != "" { s.patterns.addSchemaPattern(refURI, schema.Pattern) } for k, v := range schema.Definitions { s.analyzeSchema(k, v, slashpath.Join(refURI, "definitions")) } for k, v := range schema.Properties { s.analyzeSchema(k, v, slashpath.Join(refURI, "properties")) } for k, v := range schema.PatternProperties { s.analyzeSchema(k, v, slashpath.Join(refURI, "patternProperties")) } for i, v := range schema.AllOf { s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "allOf")) } if len(schema.AllOf) > 0 { s.allOfs["#"+refURI] = schRef } for i, v := range schema.AnyOf { s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "anyOf")) } for i, v := range schema.OneOf { s.analyzeSchema(strconv.Itoa(i), v, slashpath.Join(refURI, "oneOf")) } if schema.Not != nil { s.analyzeSchema("not", *schema.Not, refURI) } if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { s.analyzeSchema("additionalProperties", *schema.AdditionalProperties.Schema, refURI) } if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { s.analyzeSchema("additionalItems", *schema.AdditionalItems.Schema, refURI) } if schema.Items != nil { if schema.Items.Schema != nil { s.analyzeSchema("items", *schema.Items.Schema, refURI) } for i, sch := range schema.Items.Schemas { s.analyzeSchema(strconv.Itoa(i), sch, slashpath.Join(refURI, "items")) } } }
func (s splitKey) PathItemRef() swspec.Ref { if len(s) < 3 { return swspec.Ref{} } pth, method := s[1], s[2] if _, validMethod := validMethods[strings.ToUpper(method)]; !validMethod && !strings.HasPrefix(method, "x-") { return swspec.Ref{} } return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(pth), strings.ToUpper(method))) }
func TestResolveLocalRef_PathItem(t *testing.T) { rootDoc := new(Swagger) b, err := ioutil.ReadFile("fixtures/specs/refed.json") if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { var tgt PathItem ref, err := NewRef("#/paths/" + jsonpointer.Escape("/pets/{id}")) if assert.NoError(t, err) { resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) } } } }
func TestResolveRemoteRef_ToPathItem(t *testing.T) { specs := "fixtures/specs" fileserver := http.FileServer(http.Dir(specs)) server := httptest.NewServer(fileserver) defer server.Close() rootDoc := new(Swagger) b, err := ioutil.ReadFile("fixtures/specs/refed.json") if assert.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc)) { var tgt PathItem ref, err := NewRef(server.URL + "/refed.json#/paths/" + jsonpointer.Escape("/pets/{id}")) if assert.NoError(t, err) { resolver, _ := defaultSchemaLoader(rootDoc, nil, nil) if assert.NoError(t, resolver.Resolve(&ref, &tgt)) { assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get) } } } }
func gatherOperations(specDoc *Spec, operationIDs []string) map[string]opRef { var oprefs opRefs for method, pathItem := range specDoc.Operations() { for pth, operation := range pathItem { vv := *operation oprefs = append(oprefs, opRef{ Key: swag.ToGoName(strings.ToLower(method) + " " + pth), Method: method, Path: pth, ID: vv.ID, Op: &vv, Ref: swspec.MustCreateRef("#" + path.Join("/paths", jsonpointer.Escape(pth), method)), }) } } sort.Sort(oprefs) operations := make(map[string]opRef) for _, opr := range oprefs { nm := opr.ID if nm == "" { nm = opr.Key } oo, found := operations[nm] if found && oo.Method != opr.Method && oo.Path != opr.Path { nm = opr.Key } if len(operationIDs) == 0 || containsString(operationIDs, opr.ID) || containsString(operationIDs, nm) { opr.ID = nm opr.Op.ID = nm operations[nm] = opr } } return operations }
func (s splitKey) PathRef() swspec.Ref { if !s.IsOperation() { return swspec.Ref{} } return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(s[1]))) }