Beispiel #1
0
func modelValidations(gs GenSchema) commonValidations {

	return commonValidations{
		propertyDescriptor: propertyDescriptor{
			PropertyName:      swag.ToGoName(gs.Name),
			ParamName:         gs.Name,
			ValueExpression:   gs.ValueExpression,
			IndexVar:          gs.IndexVar,
			Path:              gs.Path,
			IsContainer:       gs.IsArray,
			IsPrimitive:       gs.IsPrimitive,
			IsCustomFormatter: gs.IsCustomFormatter,
			IsMap:             gs.IsMap,
		},
		sharedValidations: sharedValidations{
			Required:         gs.Required,
			Maximum:          gs.Maximum,
			ExclusiveMaximum: gs.ExclusiveMaximum,
			Minimum:          gs.Minimum,
			ExclusiveMinimum: gs.ExclusiveMinimum,
			MaxLength:        gs.MaxLength,
			MinLength:        gs.MinLength,
			Pattern:          gs.Pattern,
			MaxItems:         gs.MaxItems,
			MinItems:         gs.MinItems,
			UniqueItems:      gs.UniqueItems,
			MultipleOf:       gs.MultipleOf,
			Enum:             gs.Enum,
		},
		Type:   gs.GoType,
		Format: gs.SwaggerFormat,
		//Default:          model.Default,
	}
}
func TestSchemaValidation_RequiredProps(t *testing.T) {
	specDoc, err := spec.Load("../fixtures/codegen/todolist.schemavalidation.yml")
	if assert.NoError(t, err) {
		k := "RequiredProps"
		schema := specDoc.Spec().Definitions[k]

		gm, err := makeGenDefinition(k, "models", schema, specDoc)
		if assert.NoError(t, err) {
			assert.Len(t, gm.Properties, 6)
			for _, p := range gm.Properties {
				if assert.True(t, p.Required) {
					buf := bytes.NewBuffer(nil)
					err := modelTemplate.Execute(buf, gm)
					if assert.NoError(t, err) {
						formatted, err := formatGoFile("required_props.go", buf.Bytes())
						if assert.NoError(t, err) {
							res := string(formatted)
							assertInCode(t, k+") Validate(formats", res)
							assertInCode(t, "validate"+swag.ToGoName(p.Name), res)
							assertInCode(t, "err := validate.Required", res)
							assertInCode(t, "errors.CompositeValidationError(res...)", res)
						}
					}
				}
			}
		}
	}
}
Beispiel #3
0
func (t *typeResolver) resolveSchemaRef(schema *spec.Schema) (returns bool, result resolvedType, err error) {
	if schema.Ref.GetURL() != nil {
		returns = true
		ref, er := spec.ResolveRef(t.Doc.Spec(), &schema.Ref)
		if er != nil {
			err = er
			return
		}
		var nm = filepath.Base(schema.Ref.GetURL().Fragment)
		var tn string
		if gn, ok := ref.Extensions["x-go-name"]; ok {
			tn = gn.(string)
		} else {
			tn = swag.ToGoName(nm)
		}

		res, er := t.ResolveSchema(ref, false)
		if er != nil {
			err = er
			return
		}
		result = res
		result.GoType = tn
		if t.ModelsPackage != "" {
			result.GoType = t.ModelsPackage + "." + tn
		}
		return

	}
	return
}
Beispiel #4
0
func (sg *schemaGenContext) NewAdditionalItems(schema *spec.Schema) *schemaGenContext {
	pg := sg.shallowClone()
	indexVar := pg.IndexVar
	pg.Name = sg.Name + " items"
	itemsLen := 0
	if sg.Schema.Items != nil {
		itemsLen = sg.Schema.Items.Len()
	}
	var mod string
	if itemsLen > 0 {
		mod = "+" + strconv.Itoa(itemsLen)
	}
	if pg.Path == "" {
		pg.Path = "strconv.Itoa(" + indexVar + mod + ")"
	} else {
		pg.Path = pg.Path + "+ \".\" + strconv.Itoa(" + indexVar + mod + ")"
	}
	pg.IndexVar = indexVar
	pg.ValueExpr = sg.ValueExpr + "." + swag.ToGoName(sg.Name) + "Items[" + indexVar + "]"
	pg.Schema = spec.Schema{}
	if schema != nil {
		pg.Schema = *schema
	}
	pg.Required = false
	return pg
}
Beispiel #5
0
func (sg *schemaGenContext) buildItems() error {
	presentsAsSingle := sg.Schema.Items != nil && sg.Schema.Items.Schema != nil
	if presentsAsSingle && sg.Schema.AdditionalItems != nil { // unsure if htis a valid of invalid schema
		return fmt.Errorf("single schema (%s) can't have additional items", sg.Name)
	}
	if presentsAsSingle {
		return sg.buildArray()
	}
	if sg.Schema.Items != nil {
		// This is a tuple, build a new model that represents this
		if sg.Named {
			sg.GenSchema.Name = sg.Name
			sg.GenSchema.GoType = swag.ToGoName(sg.Name)
			if sg.TypeResolver.ModelsPackage != "" {
				sg.GenSchema.GoType = sg.TypeResolver.ModelsPackage + "." + sg.GenSchema.GoType
			}
			for i, s := range sg.Schema.Items.Schemas {
				elProp := sg.NewTupleElement(&s, i)
				if err := elProp.makeGenSchema(); err != nil {
					return err
				}
				sg.MergeResult(elProp)
				elProp.GenSchema.Name = "p" + strconv.Itoa(i)
				sg.GenSchema.Properties = append(sg.GenSchema.Properties, elProp.GenSchema)
			}
			return nil
		}

		// for an anonoymous object, first build the new object
		// and then replace the current one with a $ref to the
		// new tuple object
		var sch spec.Schema
		sch.Typed("object", "")
		sch.Properties = make(map[string]spec.Schema)
		for i, v := range sg.Schema.Items.Schemas {
			sch.Required = append(sch.Required, "P"+strconv.Itoa(i))
			sch.Properties["P"+strconv.Itoa(i)] = v
		}
		sch.AdditionalItems = sg.Schema.AdditionalItems
		tup := sg.makeNewStruct(sg.GenSchema.Name+"Tuple"+strconv.Itoa(sg.Index), sch)
		if err := tup.makeGenSchema(); err != nil {
			return err
		}
		tup.GenSchema.IsTuple = true
		tup.GenSchema.IsComplexObject = false
		tup.GenSchema.Title = tup.GenSchema.Name + " a representation of an anonymous Tuple type"
		tup.GenSchema.Description = ""
		sg.ExtraSchemas[tup.Name] = tup.GenSchema

		sg.Schema = *spec.RefProperty("#/definitions/" + tup.Name)
		if err := sg.makeGenSchema(); err != nil {
			return err
		}
		sg.MergeResult(tup)

	}
	return nil
}
Beispiel #6
0
func appNameOrDefault(specDoc *spec.Document, name, defaultName string) string {
	if name == "" {
		if specDoc.Spec().Info != nil && specDoc.Spec().Info.Title != "" {
			name = specDoc.Spec().Info.Title
		} else {
			name = defaultName
		}
	}
	return swag.ToGoName(name)
}
Beispiel #7
0
func (b *codeGenOpBuilder) MakeResponse(receiver, name string, isSuccess bool, resolver *typeResolver, resp spec.Response) (GenResponse, error) {

	res := GenResponse{
		Package:        b.APIPackage,
		ReceiverName:   receiver,
		Name:           name,
		Description:    resp.Description,
		DefaultImports: nil,
		Imports:        nil,
		IsSuccess:      isSuccess,
	}

	for hName, header := range resp.Headers {
		res.Headers = append(res.Headers, b.MakeHeader(receiver, hName, header))
	}

	if resp.Schema != nil {
		sc := schemaGenContext{
			Path:         fmt.Sprintf("%q", name),
			Name:         name + "Body",
			Receiver:     receiver,
			ValueExpr:    receiver,
			IndexVar:     "i",
			Schema:       *resp.Schema,
			Required:     true,
			TypeResolver: resolver,
			Named:        false,
			ExtraSchemas: make(map[string]GenSchema),
		}
		if err := sc.makeGenSchema(); err != nil {
			return GenResponse{}, err
		}

		for k, v := range sc.ExtraSchemas {
			b.ExtraSchemas[k] = v
		}

		schema := sc.GenSchema
		if schema.IsAnonymous {
			schema.Name = swag.ToGoName(sc.Name + " Body")
			nm := schema.Name
			if b.ExtraSchemas == nil {
				b.ExtraSchemas = make(map[string]GenSchema)
			}
			b.ExtraSchemas[schema.Name] = schema
			schema = GenSchema{}
			schema.IsAnonymous = false
			schema.GoType = nm
			schema.SwaggerType = nm
		}

		res.Schema = &schema
	}
	return res, nil
}
Beispiel #8
0
func (sg *schemaGenContext) makeNewStruct(name string, schema spec.Schema) *schemaGenContext {
	sp := sg.TypeResolver.Doc.Spec()
	name = swag.ToGoName(name)
	if sg.TypeResolver.ModelName != sg.Name {
		name = swag.ToGoName(sg.TypeResolver.ModelName + " " + name)
	}
	sp.Definitions[name] = schema
	pg := schemaGenContext{
		Path:         "",
		Name:         name,
		Receiver:     "m",
		IndexVar:     "i",
		ValueExpr:    "m",
		Schema:       schema,
		Required:     false,
		TypeResolver: sg.TypeResolver,
		Named:        true,
		ExtraSchemas: make(map[string]GenSchema),
	}
	pg.GenSchema.IsVirtual = true

	sg.ExtraSchemas[name] = pg.GenSchema
	return &pg
}
Beispiel #9
0
func (sg *schemaGenContext) NewStructBranch(name string, schema spec.Schema) *schemaGenContext {
	pg := sg.shallowClone()
	if sg.Path == "" {
		pg.Path = fmt.Sprintf("%q", name)
	} else {
		pg.Path = pg.Path + "+\".\"+" + fmt.Sprintf("%q", name)
	}
	pg.Name = name
	pg.ValueExpr = pg.ValueExpr + "." + swag.ToGoName(name)
	pg.Schema = schema
	for _, fn := range sg.Schema.Required {
		if name == fn {
			pg.Required = true
			break
		}
	}
	return pg
}
Beispiel #10
0
func paramValidations(receiver string, param spec.Parameter) commonValidations {
	accessor := swag.ToGoName(param.Name)
	paramName := swag.ToJSONName(param.Name)

	tpe := typeForParameter(param)
	_, isPrimitive := primitives[tpe]
	_, isCustomFormatter := customFormatters[tpe]

	return commonValidations{
		propertyDescriptor: propertyDescriptor{
			PropertyName:      accessor,
			ParamName:         paramName,
			ValueExpression:   fmt.Sprintf("%s.%s", receiver, accessor),
			IndexVar:          "i",
			Path:              "\"" + paramName + "\"",
			IsContainer:       param.Items != nil || tpe == "array",
			IsPrimitive:       isPrimitive,
			IsCustomFormatter: isCustomFormatter,
			IsMap:             strings.HasPrefix(tpe, "map"),
		},
		sharedValidations: sharedValidations{
			Required:         param.Required,
			Maximum:          param.Maximum,
			ExclusiveMaximum: param.ExclusiveMaximum,
			Minimum:          param.Minimum,
			ExclusiveMinimum: param.ExclusiveMinimum,
			MaxLength:        param.MaxLength,
			MinLength:        param.MinLength,
			Pattern:          param.Pattern,
			MaxItems:         param.MaxItems,
			MinItems:         param.MinItems,
			UniqueItems:      param.UniqueItems,
			MultipleOf:       param.MultipleOf,
			Enum:             param.Enum,
		},
		Type:    tpe,
		Format:  param.Format,
		Items:   param.Items,
		Default: param.Default,
	}
}
Beispiel #11
0
func fieldNameFromParam(param *Parameter) string {
	if nm, ok := param.Extensions.GetString("go-name"); ok {
		return nm
	}
	return swag.ToGoName(param.Name)
}
Beispiel #12
0
func (o *operationGenerator) Generate() error {
	// Build a list of codegen operations based on the tags,
	// the tag decides the actual package for an operation
	// the user specified package serves as root for generating the directory structure
	var operations []GenOperation
	authed := len(o.SecurityRequirements) > 0

	var bldr codeGenOpBuilder
	bldr.Name = o.Name
	bldr.ModelsPackage = o.ModelsPackage
	bldr.Principal = o.Principal
	bldr.Target = o.Target
	bldr.Operation = o.Operation
	bldr.Authed = authed
	bldr.Doc = o.Doc
	//bldr.DefaultImports = []string{filepath.ToSlash(filepath.Join(baseImport(o.Target), o.ModelsPackage))}

	for _, tag := range o.Operation.Tags {
		if len(o.Tags) == 0 {
			bldr.APIPackage = tag
			op, err := bldr.MakeOperation()
			if err != nil {
				return err
			}
			operations = append(operations, op)
			continue
		}
		for _, ft := range o.Tags {
			if ft == tag {
				bldr.APIPackage = tag
				op, err := bldr.MakeOperation()
				if err != nil {
					return err
				}
				operations = append(operations, op)
				break
			}
		}
	}
	if len(operations) == 0 {
		bldr.APIPackage = o.APIPackage
		op, err := bldr.MakeOperation()
		if err != nil {
			return err
		}
		operations = append(operations, op)
	}

	for _, op := range operations {
		if o.DumpData {
			bb, _ := json.MarshalIndent(swag.ToDynamicJSON(op), "", " ")
			fmt.Fprintln(os.Stdout, string(bb))
			continue
		}
		o.data = op
		o.pkg = op.Package
		o.cname = swag.ToGoName(op.Name)

		if o.IncludeHandler {
			if err := o.generateHandler(); err != nil {
				return fmt.Errorf("handler: %s", err)
			}
			log.Println("generated handler", op.Package+"."+o.cname)
		}

		if o.IncludeParameters && len(o.Operation.Parameters) > 0 {
			if err := o.generateParameterModel(); err != nil {
				return fmt.Errorf("parameters: %s", err)
			}
			log.Println("generated parameters", op.Package+"."+o.cname+"Parameters")
		}

		if len(o.Operation.Parameters) == 0 {
			log.Println("no parameters for operation", op.Package+"."+o.cname)
		}
	}

	return nil
}
Beispiel #13
0
func (b *codeGenOpBuilder) MakeParameter(receiver string, resolver *typeResolver, param spec.Parameter) (GenParameter, error) {
	var child *GenItems
	res := GenParameter{
		Name:             param.Name,
		Path:             fmt.Sprintf("%q", param.Name),
		ValueExpression:  fmt.Sprintf("%s.%s", receiver, swag.ToGoName(param.Name)),
		IndexVar:         "i",
		BodyParam:        nil,
		Default:          param.Default,
		Enum:             param.Enum,
		Description:      param.Description,
		ReceiverName:     receiver,
		CollectionFormat: param.CollectionFormat,
		Child:            child,
		Location:         param.In,
	}

	if param.In == "body" {
		sc := schemaGenContext{
			Path:         res.Path,
			Name:         res.Name,
			Receiver:     res.ReceiverName,
			ValueExpr:    res.ReceiverName,
			IndexVar:     res.IndexVar,
			Schema:       *param.Schema,
			Required:     param.Required,
			TypeResolver: resolver,
			Named:        false,
			ExtraSchemas: make(map[string]GenSchema),
		}
		if err := sc.makeGenSchema(); err != nil {
			return GenParameter{}, err
		}

		schema := sc.GenSchema
		if schema.IsAnonymous {
			schema.Name = swag.ToGoName(b.Operation.ID + " Body")
			nm := schema.Name
			schema.GoType = nm
			schema.IsAnonymous = false
			if b.ExtraSchemas == nil {
				b.ExtraSchemas = make(map[string]GenSchema)
			}
			b.ExtraSchemas[nm] = schema
			schema = GenSchema{}
			schema.IsAnonymous = false
			schema.GoType = nm
			schema.SwaggerType = nm
			schema.IsComplexObject = true
		}
		res.Schema = &schema
		res.resolvedType = schema.resolvedType
		res.sharedValidations = schema.sharedValidations

	} else {
		res.resolvedType = simpleResolvedType(param.Type, param.Format, param.Items)
		res.sharedValidations = sharedValidations{
			Required:         param.Required,
			Maximum:          param.Maximum,
			ExclusiveMaximum: param.ExclusiveMaximum,
			Minimum:          param.Minimum,
			ExclusiveMinimum: param.ExclusiveMinimum,
			MaxLength:        param.MaxLength,
			MinLength:        param.MinLength,
			Pattern:          param.Pattern,
			MaxItems:         param.MaxItems,
			MinItems:         param.MinItems,
			UniqueItems:      param.UniqueItems,
			MultipleOf:       param.MultipleOf,
			Enum:             param.Enum,
		}

		if param.Items != nil {
			pi, err := b.MakeParameterItem(receiver, param.Name+" "+res.IndexVar, res.IndexVar+"i", "fmt.Sprintf(\"%s.%v\", "+res.Path+", "+res.IndexVar+")", res.ValueExpression+"["+res.IndexVar+"]", resolver, param.Items, nil)
			if err != nil {
				return GenParameter{}, err
			}
			res.Child = &pi
		}

	}

	hasNumberValidation := param.Maximum != nil || param.Minimum != nil || param.MultipleOf != nil
	hasStringValidation := param.MaxLength != nil || param.MinLength != nil || param.Pattern != ""
	hasSliceValidations := param.MaxItems != nil || param.MinItems != nil || param.UniqueItems
	hasValidations := hasNumberValidation || hasStringValidation || hasSliceValidations || len(param.Enum) > 0

	res.Converter = stringConverters[res.GoType]
	res.Formatter = stringFormatters[res.GoType]
	res.HasValidations = hasValidations
	res.HasSliceValidations = hasSliceValidations
	return res, nil
}
Beispiel #14
0
func (ctx *paramTestContext) assertGenParam(t testing.TB, param spec.Parameter, gp GenParameter) bool {
	// went with the verbose option here, easier to debug
	if !assert.Equal(t, param.In, gp.Location) {
		return false
	}
	if !assert.Equal(t, param.Name, gp.Name) {
		return false
	}
	if !assert.Equal(t, fmt.Sprintf("%q", param.Name), gp.Path) {
		return false
	}
	if !assert.Equal(t, "i", gp.IndexVar) {
		return false
	}
	if !assert.Equal(t, "a", gp.ReceiverName) {
		return false
	}
	if !assert.Equal(t, "a."+swag.ToGoName(param.Name), gp.ValueExpression) {
		return false
	}
	if !assert.Equal(t, ctx.Formatter, gp.Formatter) {
		return false
	}
	if !assert.Equal(t, ctx.Converter, gp.Converter) {
		return false
	}
	if !assert.Equal(t, param.Description, gp.Description) {
		return false
	}
	if !assert.Equal(t, param.CollectionFormat, gp.CollectionFormat) {
		return false
	}
	if !assert.Equal(t, param.Required, gp.Required) {
		return false
	}
	if !assert.Equal(t, param.Minimum, gp.Minimum) || !assert.Equal(t, param.ExclusiveMinimum, gp.ExclusiveMinimum) {
		return false
	}
	if !assert.Equal(t, param.Maximum, gp.Maximum) || !assert.Equal(t, param.ExclusiveMaximum, gp.ExclusiveMaximum) {
		return false
	}
	if !assert.Equal(t, param.MinLength, gp.MinLength) {
		return false
	}
	if !assert.Equal(t, param.MaxLength, gp.MaxLength) {
		return false
	}
	if !assert.Equal(t, param.Pattern, gp.Pattern) {
		return false
	}
	if !assert.Equal(t, param.MaxItems, gp.MaxItems) {
		return false
	}
	if !assert.Equal(t, param.MinItems, gp.MinItems) {
		return false
	}
	if !assert.Equal(t, param.UniqueItems, gp.UniqueItems) {
		return false
	}
	if !assert.Equal(t, param.MultipleOf, gp.MultipleOf) {
		return false
	}
	if !assert.EqualValues(t, param.Enum, gp.Enum) {
		return false
	}
	if !assert.Equal(t, param.Type, gp.SwaggerType) {
		return false
	}
	if !assert.Equal(t, param.Format, gp.SwaggerFormat) {
		return false
	}
	// verify rendered template
	if param.In == "body" {
		if !assertBodyParam(t, param, gp) {
			return false
		}
		return true
	}

	if ctx.Items != nil {
		return ctx.Items.Assert(t, param.Items, gp.Child)
	}

	return true
}