예제 #1
0
// buildProperty converts a swagger 1.2 property to an open API property.
func buildProperty(swaggerProperty swagger.NamedModelProperty) (openAPIProperty spec.Schema, err error) {
	if swaggerProperty.Property.Ref != nil {
		return spec.Schema{
			SchemaProps: spec.SchemaProps{
				Ref: spec.MustCreateRef("#/definitions/" + *swaggerProperty.Property.Ref),
			},
		}, nil
	}
	openAPIProperty = spec.Schema{
		SchemaProps: spec.SchemaProps{
			Description: swaggerProperty.Property.Description,
			Default:     getDefaultValue(swaggerProperty.Property.DefaultValue),
			Enum:        make([]interface{}, len(swaggerProperty.Property.Enum)),
		},
	}
	for i, e := range swaggerProperty.Property.Enum {
		openAPIProperty.Enum[i] = e
	}
	openAPIProperty.Minimum, err = getFloat64OrNil(swaggerProperty.Property.Minimum)
	if err != nil {
		return spec.Schema{}, err
	}
	openAPIProperty.Maximum, err = getFloat64OrNil(swaggerProperty.Property.Maximum)
	if err != nil {
		return spec.Schema{}, err
	}
	if swaggerProperty.Property.UniqueItems != nil {
		openAPIProperty.UniqueItems = *swaggerProperty.Property.UniqueItems
	}

	if swaggerProperty.Property.Items != nil {
		if swaggerProperty.Property.Items.Ref != nil {
			openAPIProperty.Items = &spec.SchemaOrArray{
				Schema: &spec.Schema{
					SchemaProps: spec.SchemaProps{
						Ref: spec.MustCreateRef("#/definitions/" + *swaggerProperty.Property.Items.Ref),
					},
				},
			}
		} else {
			openAPIProperty.Items = &spec.SchemaOrArray{
				Schema: &spec.Schema{},
			}
			openAPIProperty.Items.Schema.Type, openAPIProperty.Items.Schema.Format, err =
				buildType(swaggerProperty.Property.Items.Type, swaggerProperty.Property.Items.Format)
			if err != nil {
				return spec.Schema{}, err
			}
		}
	}
	openAPIProperty.Type, openAPIProperty.Format, err =
		buildType(swaggerProperty.Property.Type, swaggerProperty.Property.Format)
	if err != nil {
		return spec.Schema{}, err
	}
	return openAPIProperty, nil
}
예제 #2
0
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),
	}
	s.allSchemas["#"+refURI] = schRef
	if schema.Ref.String() != "" {
		s.references.addSchemaRef(refURI, schRef)
	}
	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] = SchemaRef{Name: name, Schema: &schema, Ref: spec.MustCreateRef("#" + refURI)}
	}
	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"))
		}
	}
}
예제 #3
0
func getRefSchema(ref string) *spec.Schema {
	return &spec.Schema{
		SchemaProps: spec.SchemaProps{
			Ref: spec.MustCreateRef(ref),
		},
	}
}
예제 #4
0
func (isn *inlineSchemaNamer) Name(key string, schema *swspec.Schema, aschema *AnalyzedSchema) error {
	if swspec.Debug {
		log.Printf("naming inlined schema at %s", key)
	}

	parts := keyParts(key)
	for _, name := range namesFromKey(parts, aschema, isn.Operations) {
		if name != "" {
			// create unique name
			newName := uniqifyName(isn.Spec.Definitions, swag.ToJSONName(name))

			// clone schema
			sch, err := cloneSchema(schema)
			if err != nil {
				return err
			}

			// replace values on schema
			if err := rewriteSchemaToRef(isn.Spec, key, swspec.MustCreateRef("#/definitions/"+newName)); err != nil {
				return fmt.Errorf("name inlined schema: %v", err)
			}

			sch.AddExtension("x-go-gen-location", genLocation(parts))
			// fmt.Printf("{\n  %q,\n  \"\",\n  spec.MustCreateRef(%q),\n  \"\",\n},\n", key, "#/definitions/"+newName)
			// save cloned schema to definitions
			saveSchema(isn.Spec, newName, sch)
		}
	}
	return nil
}
예제 #5
0
func knownRefs(base string) []spec.Ref {
	urls := []string{"bool", "string", "integer", "float", "date", "object", "format"}

	var result []spec.Ref
	for _, u := range urls {
		result = append(result, spec.MustCreateRef(fmt.Sprintf("%s/%s", base, path.Join("known", u))))
	}
	return result
}
예제 #6
0
func complexRefs(base string) []spec.Ref {
	urls := []string{"object", "array", "map"}

	var result []spec.Ref
	for _, u := range urls {
		result = append(result, spec.MustCreateRef(fmt.Sprintf("%s/%s", base, path.Join("complex", u))))
	}
	return result
}
예제 #7
0
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)))
}
예제 #8
0
func specSchemaFromJsonType(schema *jsonschema.Type) *spec.Schema {
	s := &spec.Schema{}
	if schema.Type != "" {
		s.Type = []string{schema.Type}
	}
	if schema.Ref != "" {
		s.Ref = spec.MustCreateRef(schema.Ref)
	}

	s.Format = schema.Format
	s.Required = schema.Required

	// currently there is no way to determine whether there is MaxLength or MinLength
	// defined. Need to fix jsonschema library and switch type from int to *int
	// s.MaxLength = schema.MaxLength
	// s.MinLength = schema.MinLength
	s.Pattern = schema.Pattern
	s.Enum = schema.Enum
	s.Default = schema.Default
	s.Title = schema.Title
	s.Description = schema.Description

	if schema.Items != nil {
		s.Items = &spec.SchemaOrArray{}
		s.Items.Schema = specSchemaFromJsonType(schema.Items)
	}

	if schema.Properties != nil {
		s.Properties = make(map[string]spec.Schema)
		for key, prop := range schema.Properties {
			s.Properties[key] = *specSchemaFromJsonType(prop)
		}
	}

	if schema.PatternProperties != nil {
		s.PatternProperties = make(map[string]spec.Schema)
		for key, prop := range schema.PatternProperties {
			s.PatternProperties[key] = *specSchemaFromJsonType(prop)
		}
	}

	switch string(schema.AdditionalProperties) {
	case "true":
		s.AdditionalProperties = &spec.SchemaOrBool{Allows: true}
	case "false":
		s.AdditionalProperties = &spec.SchemaOrBool{Allows: false}
	}

	return s
}
예제 #9
0
func TestNameFromRef(t *testing.T) {
	values := []struct{ Source, Expected string }{
		{"#/definitions/errorModel", "errorModel"},
		{"http://somewhere.com/definitions/errorModel", "errorModel"},
		{"http://somewhere.com/definitions/errorModel.json", "errorModel"},
		{"/definitions/errorModel", "errorModel"},
		{"/definitions/errorModel.json", "errorModel"},
		{"http://somewhere.com", "somewhereCom"},
		{"#", ""},
	}

	for _, v := range values {
		assert.Equal(t, v.Expected, nameFromRef(spec.MustCreateRef(v.Source)))
	}
}
예제 #10
0
func TestDefinitionName(t *testing.T) {
	values := []struct {
		Source, Expected string
		Definitions      spec.Definitions
	}{
		{"#/definitions/errorModel", "errorModel", map[string]spec.Schema(nil)},
		{"http://somewhere.com/definitions/errorModel", "errorModel", map[string]spec.Schema(nil)},
		{"#/definitions/errorModel", "errorModel", map[string]spec.Schema{"apples": *spec.StringProperty()}},
		{"#/definitions/errorModel", "errorModelOAIGen", map[string]spec.Schema{"errorModel": *spec.StringProperty()}},
		{"#/definitions/errorModel", "errorModelOAIGen1", map[string]spec.Schema{"errorModel": *spec.StringProperty(), "errorModelOAIGen": *spec.StringProperty()}},
		{"#", "oaiGen", nil},
	}

	for _, v := range values {
		assert.Equal(t, v.Expected, uniqifyName(v.Definitions, nameFromRef(spec.MustCreateRef(v.Source))))
	}
}
예제 #11
0
func buildParameter(restParam restful.ParameterData) (ret spec.Parameter, err error) {
	ret = spec.Parameter{
		ParamProps: spec.ParamProps{
			Name:        restParam.Name,
			Description: restParam.Description,
			Required:    restParam.Required,
		},
	}
	switch restParam.Kind {
	case restful.BodyParameterKind:
		ret.In = "body"
		ret.Schema = &spec.Schema{
			SchemaProps: spec.SchemaProps{
				Ref: spec.MustCreateRef("#/definitions/" + restParam.DataType),
			},
		}
		return ret, nil
	case restful.PathParameterKind:
		ret.In = "path"
		if !restParam.Required {
			return ret, fmt.Errorf("Path parameters should be marked at required for parameter %v", restParam)
		}
	case restful.QueryParameterKind:
		ret.In = "query"
	case restful.HeaderParameterKind:
		ret.In = "header"
	case restful.FormParameterKind:
		ret.In = "form"
	default:
		return ret, fmt.Errorf("Unknown restful operation kind : %v", restParam.Kind)
	}
	if !isSimpleDataType(restParam.DataType) {
		return ret, fmt.Errorf("Restful DataType should be a simple type, but got : %v", restParam.DataType)
	}
	ret.Type = restParam.DataType
	ret.Format = restParam.DataFormat
	ret.UniqueItems = !restParam.AllowMultiple
	// TODO(mbohlool): make sure the type of default value matches Type
	if restParam.DefaultValue != "" {
		ret.Default = restParam.DefaultValue
	}

	return ret, nil
}
예제 #12
0
// buildOperations builds operations for each webservice path
func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map[interface{}]spec.Parameter) (*spec.Operation, error) {
	ret := &spec.Operation{
		OperationProps: spec.OperationProps{
			Description: route.Doc,
			Consumes:    route.Consumes,
			Produces:    route.Produces,
			ID:          route.Operation,
			Schemes:     o.protocolList,
			Responses: &spec.Responses{
				ResponsesProps: spec.ResponsesProps{
					StatusCodeResponses: make(map[int]spec.Response),
				},
			},
		},
	}
	for _, resp := range route.ResponseErrors {
		ret.Responses.StatusCodeResponses[resp.Code] = spec.Response{
			ResponseProps: spec.ResponseProps{
				Description: resp.Message,
				Schema: &spec.Schema{
					SchemaProps: spec.SchemaProps{
						Ref: spec.MustCreateRef("#/definitions/" + reflect.TypeOf(resp.Model).String()),
					},
				},
			},
		}
	}
	if len(ret.Responses.StatusCodeResponses) == 0 {
		ret.Responses.Default = o.config.DefaultResponse
	}
	ret.Parameters = make([]spec.Parameter, 0)
	for _, param := range route.ParameterDocs {
		_, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]
		if !isCommon {
			openAPIParam, err := buildParameter(param.Data())
			if err != nil {
				return ret, err
			}
			ret.Parameters = append(ret.Parameters, openAPIParam)
		}
	}
	sort.Sort(orderedParameters(ret.Parameters))
	return ret, nil
}
예제 #13
0
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
}
예제 #14
0
func importExternalReferences(opts *FlattenOpts) error {
	groupedRefs := reverseIndexForSchemaRefs(opts)

	for refStr, entry := range groupedRefs {
		if !entry.Ref.HasFragmentOnly {
			if swspec.Debug {
				log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
			}
			// resolve to actual schema
			sch, err := swspec.ResolveRefWithBase(opts.Swagger(), &entry.Ref, opts.ExpandOpts(false))
			if err != nil {
				return err
			}
			if sch == nil {
				return fmt.Errorf("no schema found at %s for [%s]", refStr, strings.Join(entry.Keys, ", "))
			}
			if swspec.Debug {
				log.Printf("importing external schema for [%s] from %s", strings.Join(entry.Keys, ", "), refStr)
			}

			// generate a unique name
			newName := uniqifyName(opts.Swagger().Definitions, nameFromRef(entry.Ref))
			if swspec.Debug {
				log.Printf("new name for [%s]: %s", strings.Join(entry.Keys, ", "), newName)
			}

			// rewrite the external refs to local ones
			for _, key := range entry.Keys {
				if err := updateRef(opts.Swagger(), key, swspec.MustCreateRef("#"+path.Join("/definitions", newName))); err != nil {
					return err
				}
			}

			// add the resolved schema to the definitions
			saveSchema(opts.Swagger(), newName, sch)
		}
	}
	return nil
}
예제 #15
0
func (o *openAPI) toSchema(typeName string, model interface{}) (_ *spec.Schema, err error) {
	if openAPIType, openAPIFormat := common.GetOpenAPITypeFormat(typeName); openAPIType != "" {
		return &spec.Schema{
			SchemaProps: spec.SchemaProps{
				Type:   []string{openAPIType},
				Format: openAPIFormat,
			},
		}, nil
	} else {
		ref := "#/definitions/" + typeName
		if model != nil {
			ref, err = o.buildDefinitionForType(model)
			if err != nil {
				return nil, err
			}
		}
		return &spec.Schema{
			SchemaProps: spec.SchemaProps{
				Ref: spec.MustCreateRef(ref),
			},
		}, nil
	}
}
예제 #16
0
func TestNameInlinedSchemas(t *testing.T) {
	bp := filepath.Join(".", "fixtures", "nested_inline_schemas.yml")
	sp, err := loadSpec(bp)
	values := []struct {
		Key      string
		Location string
		Ref      spec.Ref
	}{
		{"#/paths/~1some~1where~1{id}/parameters/1/schema/items", "#/definitions/postSomeWhereIdParamsBody/items", spec.MustCreateRef("#/definitions/postSomeWhereIdParamsBodyItems")},
		{"#/paths/~1some~1where~1{id}/parameters/1/schema", "#/paths/~1some~1where~1{id}/parameters/1/schema", spec.MustCreateRef("#/definitions/postSomeWhereIdParamsBody")},
		{"#/paths/~1some~1where~1{id}/get/parameters/2/schema/properties/record/items/2/properties/name", "#/definitions/getSomeWhereIdParamsBodyRecordItems2/properties/name", spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems2Name")},
		{"#/paths/~1some~1where~1{id}/get/parameters/2/schema/properties/record/items/1", "#/definitions/getSomeWhereIdParamsBodyRecord/items/1", spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems1")},
		{"#/paths/~1some~1where~1{id}/get/parameters/2/schema/properties/record/items/2", "#/definitions/getSomeWhereIdParamsBodyRecord/items/2", spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems2")},
		{"#/paths/~1some~1where~1{id}/get/parameters/2/schema/properties/record", "#/definitions/getSomeWhereIdParamsBodyOAIGen/properties/record", spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecord")},
		{"#/paths/~1some~1where~1{id}/get/parameters/2/schema", "#/paths/~1some~1where~1{id}/get/parameters/2/schema", spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyOAIGen")},
		{"#/paths/~1some~1where~1{id}/get/responses/200/schema/properties/record/items/2/properties/name", "#/definitions/getSomeWhereIdOKBodyRecordItems2/properties/name", spec.MustCreateRef("#/definitions/getSomeWhereIdOKBodyRecordItems2Name")},
		{"#/paths/~1some~1where~1{id}/get/responses/200/schema/properties/record/items/1", "#/definitions/getSomeWhereIdOKBodyRecord/items/1", spec.MustCreateRef("#/definitions/getSomeWhereIdOKBodyRecordItems1")},
		{"#/paths/~1some~1where~1{id}/get/responses/200/schema/properties/record/items/2", "#/definitions/getSomeWhereIdOKBodyRecord/items/2", spec.MustCreateRef("#/definitions/getSomeWhereIdOKBodyRecordItems2")},
		{"#/paths/~1some~1where~1{id}/get/responses/200/schema/properties/record", "#/definitions/getSomeWhereIdOKBody/properties/record", spec.MustCreateRef("#/definitions/getSomeWhereIdOKBodyRecord")},
		{"#/paths/~1some~1where~1{id}/get/responses/200/schema", "#/paths/~1some~1where~1{id}/get/responses/200/schema", spec.MustCreateRef("#/definitions/getSomeWhereIdOKBody")},
		{"#/paths/~1some~1where~1{id}/get/responses/default/schema/properties/record/items/2/properties/name", "#/definitions/getSomeWhereIdDefaultBodyRecordItems2/properties/name", spec.MustCreateRef("#/definitions/getSomeWhereIdDefaultBodyRecordItems2Name")},
		{"#/paths/~1some~1where~1{id}/get/responses/default/schema/properties/record/items/1", "#/definitions/getSomeWhereIdDefaultBodyRecord/items/1", spec.MustCreateRef("#/definitions/getSomeWhereIdDefaultBodyRecordItems1")},
		{"#/paths/~1some~1where~1{id}/get/responses/default/schema/properties/record/items/2", "#/definitions/getSomeWhereIdDefaultBodyRecord/items/2", spec.MustCreateRef("#/definitions/getSomeWhereIdDefaultBodyRecordItems2")},
		{"#/paths/~1some~1where~1{id}/get/responses/default/schema/properties/record", "#/definitions/getSomeWhereIdDefaultBody/properties/record", spec.MustCreateRef("#/definitions/getSomeWhereIdDefaultBodyRecord")},
		{"#/paths/~1some~1where~1{id}/get/responses/default/schema", "#/paths/~1some~1where~1{id}/get/responses/default/schema", spec.MustCreateRef("#/definitions/getSomeWhereIdDefaultBody")},
		{"#/definitions/nestedThing/properties/record/items/2/allOf/1/additionalProperties", "#/definitions/nestedThingRecordItems2AllOf1/additionalProperties", spec.MustCreateRef("#/definitions/nestedThingRecordItems2AllOf1AdditionalProperties")},
		{"#/definitions/nestedThing/properties/record/items/2/allOf/1", "#/definitions/nestedThingRecordItems2/allOf/1", spec.MustCreateRef("#/definitions/nestedThingRecordItems2AllOf1")},
		{"#/definitions/nestedThing/properties/record/items/2/properties/name", "#/definitions/nestedThingRecordItems2/properties/name", spec.MustCreateRef("#/definitions/nestedThingRecordItems2Name")},
		{"#/definitions/nestedThing/properties/record/items/1", "#/definitions/nestedThingRecord/items/1", spec.MustCreateRef("#/definitions/nestedThingRecordItems1")},
		{"#/definitions/nestedThing/properties/record/items/2", "#/definitions/nestedThingRecord/items/2", spec.MustCreateRef("#/definitions/nestedThingRecordItems2")},
		{"#/definitions/datedRecords/items/1", "#/definitions/datedRecords/items/1", spec.MustCreateRef("#/definitions/datedRecordsItems1")},
		{"#/definitions/datedTaggedRecords/items/1", "#/definitions/datedTaggedRecords/items/1", spec.MustCreateRef("#/definitions/datedTaggedRecordsItems1")},
		{"#/definitions/namedThing/properties/name", "#/definitions/namedThing/properties/name", spec.MustCreateRef("#/definitions/namedThingName")},
		{"#/definitions/nestedThing/properties/record", "#/definitions/nestedThing/properties/record", spec.MustCreateRef("#/definitions/nestedThingRecord")},
		{"#/definitions/records/items/0", "#/definitions/records/items/0", spec.MustCreateRef("#/definitions/recordsItems0")},
		{"#/definitions/datedTaggedRecords/additionalItems", "#/definitions/datedTaggedRecords/additionalItems", spec.MustCreateRef("#/definitions/datedTaggedRecordsItemsAdditionalItems")},
		{"#/definitions/otherRecords/items", "#/definitions/otherRecords/items", spec.MustCreateRef("#/definitions/otherRecordsItems")},
		{"#/definitions/tags/additionalProperties", "#/definitions/tags/additionalProperties", spec.MustCreateRef("#/definitions/tagsAdditionalProperties")},
	}
	if assert.NoError(t, err) {
		err := nameInlinedSchemas(&FlattenOpts{
			Spec:     New(sp),
			BasePath: bp,
		})

		if assert.NoError(t, err) {
			for i, v := range values {
				ptr, err := jsonpointer.New(v.Location[1:])
				if assert.NoError(t, err, "at %d for %s", i, v.Key) {
					vv, _, err := ptr.Get(sp)

					if assert.NoError(t, err, "at %d for %s", i, v.Key) {
						switch tv := vv.(type) {
						case *spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String(), "at %d for %s", i, v.Key)
						case spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String(), "at %d for %s", i, v.Key)
						case *spec.SchemaOrBool:
							var sRef spec.Ref
							if tv != nil && tv.Schema != nil {
								sRef = tv.Schema.Ref
							}
							assert.Equal(t, v.Ref.String(), sRef.String(), "at %d for %s", i, v.Key)
						case *spec.SchemaOrArray:
							var sRef spec.Ref
							if tv != nil && tv.Schema != nil {
								sRef = tv.Schema.Ref
							}
							assert.Equal(t, v.Ref.String(), sRef.String(), "at %d for %s", i, v.Key)
						default:
							assert.Fail(t, "unknown type", "got %T", vv)
						}
					}
				}
			}
		}

		for k, rr := range New(sp).allSchemas {
			if !strings.HasPrefix(k, "#/responses") && !strings.HasPrefix(k, "#/parameters") {
				if rr.Schema != nil && rr.Schema.Ref.String() == "" && !rr.TopLevel {
					asch, err := Schema(SchemaOpts{Schema: rr.Schema, Root: sp, BasePath: bp})
					if assert.NoError(t, err, "for key: %s", k) {
						if !asch.IsSimpleSchema {
							assert.Fail(t, "not a top level schema", "for key: %s", k)
						}
					}
				}
			}
		}
	}
}
예제 #17
0
func (s splitKey) PathRef() swspec.Ref {
	if !s.IsOperation() {
		return swspec.Ref{}
	}
	return swspec.MustCreateRef("#" + path.Join("/", pths, jsonpointer.Escape(s[1])))
}
예제 #18
0
func TestImportExternalReferences(t *testing.T) {
	bp := filepath.Join(".", "fixtures", "external_definitions.yml")
	sp, err := loadSpec(bp)
	if assert.NoError(t, err) {

		values := []struct {
			Key string
			Ref spec.Ref
		}{
			{"#/parameters/someParam/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/parameters/1/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/parameters/2/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/responses/someResponse/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/responses/default/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/responses/200/schema", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/namedAgain", spec.MustCreateRef("#/definitions/named")},
			{"#/definitions/datedTag/allOf/1", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/datedRecords/items/1", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/datedTaggedRecords/items/1", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/datedTaggedRecords/additionalItems", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/otherRecords/items", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/tags/additionalProperties", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/namedThing/properties/name", spec.MustCreateRef("#/definitions/named")},
		}
		for _, v := range values {
			// technically not necessary to run for each value, but if things go right
			// this is idempotent, so having it repeat shouldn't matter
			// this validates that behavior
			err := importExternalReferences(&FlattenOpts{
				Spec:     New(sp),
				BasePath: bp,
			})

			if assert.NoError(t, err) {

				ptr, err := jsonpointer.New(v.Key[1:])
				if assert.NoError(t, err) {
					vv, _, err := ptr.Get(sp)

					if assert.NoError(t, err) {
						switch tv := vv.(type) {
						case *spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String(), "for %s", v.Key)
						case spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String(), "for %s", v.Key)
						case *spec.SchemaOrBool:
							assert.Equal(t, v.Ref.String(), tv.Schema.Ref.String(), "for %s", v.Key)
						case *spec.SchemaOrArray:
							assert.Equal(t, v.Ref.String(), tv.Schema.Ref.String(), "for %s", v.Key)
						default:
							assert.Fail(t, "unknown type", "got %T", vv)
						}
					}
				}
			}
		}
		assert.Len(t, sp.Definitions, 11)
		assert.Contains(t, sp.Definitions, "tag")
		assert.Contains(t, sp.Definitions, "named")
		assert.Contains(t, sp.Definitions, "record")
	}
}
예제 #19
0
func TestSplitKey(t *testing.T) {

	type KeyFlag uint64

	const (
		isOperation KeyFlag = 1 << iota
		isDefinition
		isSharedOperationParam
		isOperationParam
		isOperationResponse
		isDefaultResponse
		isStatusCodeResponse
	)

	values := []struct {
		Key         string
		Flags       KeyFlag
		PathItemRef spec.Ref
		PathRef     spec.Ref
		Name        string
	}{
		{
			"#/paths/~1some~1where~1{id}/parameters/1/schema",
			isOperation | isSharedOperationParam,
			spec.Ref{},
			spec.MustCreateRef("#/paths/~1some~1where~1{id}"),
			"",
		},
		{
			"#/paths/~1some~1where~1{id}/get/parameters/2/schema",
			isOperation | isOperationParam,
			spec.MustCreateRef("#/paths/~1some~1where~1{id}/GET"),
			spec.MustCreateRef("#/paths/~1some~1where~1{id}"),
			"",
		},
		{
			"#/paths/~1some~1where~1{id}/get/responses/default/schema",
			isOperation | isOperationResponse | isDefaultResponse,
			spec.MustCreateRef("#/paths/~1some~1where~1{id}/GET"),
			spec.MustCreateRef("#/paths/~1some~1where~1{id}"),
			"Default",
		},
		{
			"#/paths/~1some~1where~1{id}/get/responses/200/schema",
			isOperation | isOperationResponse | isStatusCodeResponse,
			spec.MustCreateRef("#/paths/~1some~1where~1{id}/GET"),
			spec.MustCreateRef("#/paths/~1some~1where~1{id}"),
			"OK",
		},
		{
			"#/definitions/namedAgain",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"namedAgain",
		},
		{
			"#/definitions/datedRecords/items/1",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"datedRecords",
		},
		{
			"#/definitions/datedRecords/items/1",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"datedRecords",
		},
		{
			"#/definitions/datedTaggedRecords/items/1",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"datedTaggedRecords",
		},
		{
			"#/definitions/datedTaggedRecords/additionalItems",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"datedTaggedRecords",
		},
		{
			"#/definitions/otherRecords/items",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"otherRecords",
		},
		{
			"#/definitions/tags/additionalProperties",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"tags",
		},
		{
			"#/definitions/namedThing/properties/name",
			isDefinition,
			spec.Ref{},
			spec.Ref{},
			"namedThing",
		},
	}

	for i, v := range values {
		parts := keyParts(v.Key)
		pref := parts.PathRef()
		piref := parts.PathItemRef()
		assert.Equal(t, v.PathRef.String(), pref.String(), "pathRef: %s at %d", v.Key, i)
		assert.Equal(t, v.PathItemRef.String(), piref.String(), "pathItemRef: %s at %d", v.Key, i)

		if v.Flags&isOperation != 0 {
			assert.True(t, parts.IsOperation(), "isOperation: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsOperation(), "isOperation: %s at %d", v.Key, i)
		}
		if v.Flags&isDefinition != 0 {
			assert.True(t, parts.IsDefinition(), "isDefinition: %s at %d", v.Key, i)
			assert.Equal(t, v.Name, parts.DefinitionName(), "definition name: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsDefinition(), "isDefinition: %s at %d", v.Key, i)
			if v.Name != "" {
				assert.Equal(t, v.Name, parts.ResponseName(), "response name: %s at %d", v.Key, i)
			}
		}
		if v.Flags&isOperationParam != 0 {
			assert.True(t, parts.IsOperationParam(), "isOperationParam: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsOperationParam(), "isOperationParam: %s at %d", v.Key, i)
		}
		if v.Flags&isSharedOperationParam != 0 {
			assert.True(t, parts.IsSharedOperationParam(), "isSharedOperationParam: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsSharedOperationParam(), "isSharedOperationParam: %s at %d", v.Key, i)
		}
		if v.Flags&isOperationResponse != 0 {
			assert.True(t, parts.IsOperationResponse(), "isOperationResponse: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsOperationResponse(), "isOperationResponse: %s at %d", v.Key, i)
		}
		if v.Flags&isDefaultResponse != 0 {
			assert.True(t, parts.IsDefaultResponse(), "isDefaultResponse: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsDefaultResponse(), "isDefaultResponse: %s at %d", v.Key, i)
		}
		if v.Flags&isStatusCodeResponse != 0 {
			assert.True(t, parts.IsStatusCodeResponse(), "isStatusCodeResponse: %s at %d", v.Key, i)
		} else {
			assert.False(t, parts.IsStatusCodeResponse(), "isStatusCodeResponse: %s at %d", v.Key, i)
		}
	}
}
예제 #20
0
func TestUpdateRef(t *testing.T) {
	bp := filepath.Join("fixtures", "external_definitions.yml")
	sp, err := loadSpec(bp)
	if assert.NoError(t, err) {

		values := []struct {
			Key string
			Ref spec.Ref
		}{
			{"#/parameters/someParam/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/parameters/1/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/parameters/2/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/responses/someResponse/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/responses/default/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/paths/~1some~1where~1{id}/get/responses/200/schema", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/namedAgain", spec.MustCreateRef("#/definitions/named")},
			{"#/definitions/datedTag/allOf/1", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/datedRecords/items/1", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/datedTaggedRecords/items/1", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/datedTaggedRecords/additionalItems", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/otherRecords/items", spec.MustCreateRef("#/definitions/record")},
			{"#/definitions/tags/additionalProperties", spec.MustCreateRef("#/definitions/tag")},
			{"#/definitions/namedThing/properties/name", spec.MustCreateRef("#/definitions/named")},
		}

		for _, v := range values {
			err := updateRef(sp, v.Key, v.Ref)
			if assert.NoError(t, err) {
				ptr, err := jsonpointer.New(v.Key[1:])
				if assert.NoError(t, err) {
					vv, _, err := ptr.Get(sp)

					if assert.NoError(t, err) {
						switch tv := vv.(type) {
						case *spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String())
						case spec.Schema:
							assert.Equal(t, v.Ref.String(), tv.Ref.String())
						case *spec.SchemaOrBool:
							assert.Equal(t, v.Ref.String(), tv.Schema.Ref.String())
						case *spec.SchemaOrArray:
							assert.Equal(t, v.Ref.String(), tv.Schema.Ref.String())
						default:
							assert.Fail(t, "unknown type", "got %T", vv)
						}
					}
				}
			}
		}
	}
}
예제 #21
0
func TestFlatten(t *testing.T) {
	bp := filepath.Join(".", "fixtures", "flatten.yml")
	sp, err := loadSpec(bp)
	values := []struct {
		Key      string
		Location string
		Ref      spec.Ref
		Expected interface{}
	}{
		{
			"#/responses/notFound/schema",
			"#/responses/notFound/schema",
			spec.MustCreateRef("#/definitions/error"),
			nil,
		},
		{
			"#/paths/~1some~1where~1{id}/parameters/0",
			"#/paths/~1some~1where~1{id}/parameters/0/name",
			spec.Ref{},
			"id",
		},
		{
			"#/paths/~1other~1place",
			"#/paths/~1other~1place/get/operationId",
			spec.Ref{},
			"modelOp",
		},
		{
			"#/paths/~1some~1where~1{id}/get/parameters/0",
			"#/paths/~1some~1where~1{id}/get/parameters/0/name",
			spec.Ref{},
			"limit",
		},
		{
			"#/paths/~1some~1where~1{id}/get/parameters/1",
			"#/paths/~1some~1where~1{id}/get/parameters/1/name",
			spec.Ref{},
			"some",
		},
		{
			"#/paths/~1some~1where~1{id}/get/parameters/2",
			"#/paths/~1some~1where~1{id}/get/parameters/2/name",
			spec.Ref{},
			"other",
		},
		{
			"#/paths/~1some~1where~1{id}/get/parameters/3",
			"#/paths/~1some~1where~1{id}/get/parameters/3/schema",
			spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBody"),
			"",
		},
		{
			"#/paths/~1some~1where~1{id}/get/responses/200",
			"#/paths/~1some~1where~1{id}/get/responses/200/schema",
			spec.MustCreateRef("#/definitions/getSomeWhereIdOKBody"),
			"",
		},
		{
			"#/definitions/namedAgain",
			"",
			spec.MustCreateRef("#/definitions/named"),
			"",
		},
		{
			"#/definitions/namedThing/properties/name",
			"",
			spec.MustCreateRef("#/definitions/named"),
			"",
		},
		{
			"#/definitions/namedThing/properties/namedAgain",
			"",
			spec.MustCreateRef("#/definitions/namedAgain"),
			"",
		},
		{
			"#/definitions/datedRecords/items/1",
			"",
			spec.MustCreateRef("#/definitions/record"),
			"",
		},
		{
			"#/definitions/otherRecords/items",
			"",
			spec.MustCreateRef("#/definitions/record"),
			"",
		},
		{
			"#/definitions/tags/additionalProperties",
			"",
			spec.MustCreateRef("#/definitions/tag"),
			"",
		},
		{
			"#/definitions/datedTag/allOf/1",
			"",
			spec.MustCreateRef("#/definitions/tag"),
			"",
		},
		{
			"#/definitions/nestedThingRecordItems2/allOf/1",
			"",
			spec.MustCreateRef("#/definitions/nestedThingRecordItems2AllOf1"),
			"",
		},
		{
			"#/definitions/nestedThingRecord/items/1",
			"",
			spec.MustCreateRef("#/definitions/nestedThingRecordItems1"),
			"",
		},
		{
			"#/definitions/nestedThingRecord/items/2",
			"",
			spec.MustCreateRef("#/definitions/nestedThingRecordItems2"),
			"",
		},
		{
			"#/definitions/nestedThing/properties/record",
			"",
			spec.MustCreateRef("#/definitions/nestedThingRecord"),
			"",
		},
		{
			"#/definitions/named",
			"#/definitions/named/type",
			spec.Ref{},
			spec.StringOrArray{"string"},
		},
		{
			"#/definitions/error",
			"#/definitions/error/properties/id/type",
			spec.Ref{},
			spec.StringOrArray{"integer"},
		},
		{
			"#/definitions/record",
			"#/definitions/record/properties/createdAt/format",
			spec.Ref{},
			"date-time",
		},
		{
			"#/definitions/getSomeWhereIdOKBody",
			"#/definitions/getSomeWhereIdOKBody/properties/record",
			spec.MustCreateRef("#/definitions/nestedThing"),
			nil,
		},
		{
			"#/definitions/getSomeWhereIdParamsBody",
			"#/definitions/getSomeWhereIdParamsBody/properties/record",
			spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecord"),
			nil,
		},
		{
			"#/definitions/getSomeWhereIdParamsBodyRecord",
			"#/definitions/getSomeWhereIdParamsBodyRecord/items/1",
			spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems1"),
			nil,
		},
		{
			"#/definitions/getSomeWhereIdParamsBodyRecord",
			"#/definitions/getSomeWhereIdParamsBodyRecord/items/2",
			spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems2"),
			nil,
		},
		{
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2",
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2/allOf/0/format",
			spec.Ref{},
			"date",
		},
		{
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2Name",
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2Name/properties/createdAt/format",
			spec.Ref{},
			"date-time",
		},
		{
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2",
			"#/definitions/getSomeWhereIdParamsBodyRecordItems2/properties/name",
			spec.MustCreateRef("#/definitions/getSomeWhereIdParamsBodyRecordItems2Name"),
			"date",
		},
	}
	if assert.NoError(t, err) {
		err := Flatten(FlattenOpts{Spec: New(sp), BasePath: bp})
		if assert.NoError(t, err) {
			for i, v := range values {
				pk := v.Key[1:]
				if v.Location != "" {
					pk = v.Location[1:]
				}
				ptr, err := jsonpointer.New(pk)
				if assert.NoError(t, err, "at %d for %s", i, v.Key) {
					d, _, err := ptr.Get(sp)
					if assert.NoError(t, err) {
						if v.Ref.String() != "" {
							switch s := d.(type) {
							case *spec.Schema:
								assert.Equal(t, v.Ref.String(), s.Ref.String(), "at %d for %s", i, v.Key)
							case spec.Schema:
								assert.Equal(t, v.Ref.String(), s.Ref.String(), "at %d for %s", i, v.Key)
							case *spec.SchemaOrArray:
								var sRef spec.Ref
								if s != nil && s.Schema != nil {
									sRef = s.Schema.Ref
								}
								assert.Equal(t, v.Ref.String(), sRef.String(), "at %d for %s", i, v.Key)
							case *spec.SchemaOrBool:
								var sRef spec.Ref
								if s != nil && s.Schema != nil {
									sRef = s.Schema.Ref
								}
								assert.Equal(t, v.Ref.String(), sRef.String(), "at %d for %s", i, v.Key)
							default:
								assert.Fail(t, "unknown type", "got %T at %d for %s", d, i, v.Key)
							}
						} else {
							assert.Equal(t, v.Expected, d)
						}
					}
				}
			}
		}
	}
}