func pascalize(arg string) string { if len(arg) == 0 || arg[0] > '9' { return swag.ToGoName(arg) } return swag.ToGoName("Nr " + arg) }
func (a *appGenerator) generateAPIBuilder(app *GenApp) error { buf := bytes.NewBuffer(nil) if err := builderTemplate.Execute(buf, app); err != nil { return err } log.Println("rendered builder template:", app.Package+"."+swag.ToGoName(app.Name)) return writeToFile(filepath.Join(a.Target, a.ServerPackage, app.Package), swag.ToGoName(app.Name)+"Api", buf.Bytes()) }
func (t *typeResolver) goTypeName(nm string) string { if t.ModelsPackage == "" { return swag.ToGoName(nm) } if _, ok := t.KnownDefs[nm]; ok { return strings.Join([]string{t.ModelsPackage, swag.ToGoName(nm)}, ".") } return swag.ToGoName(nm) }
func (c *clientGenerator) generateEmbeddedSwaggerJSON(app *GenApp) error { buf := bytes.NewBuffer(nil) if err := embeddedSpecTemplate.Execute(buf, app); err != nil { return err } log.Println("rendered client embedded swagger JSON template:", c.ClientPackage+"."+swag.ToGoName(app.Name)+"Client") fp := filepath.Join(c.Target, c.ClientPackage) return writeToFile(fp, swag.ToGoName(app.Name)+"EmbeddedSpec", buf.Bytes()) }
func (c *clientGenerator) generateGroupClient(opGroup GenOperationGroup) error { buf := bytes.NewBuffer(nil) if err := clientTemplate.Execute(buf, opGroup); err != nil { return err } log.Println("rendered operation group client template:", opGroup.Name+"."+swag.ToGoName(opGroup.Name)+"Client") fp := filepath.Join(c.Target, c.ClientPackage, opGroup.Name) return writeToFile(fp, swag.ToGoName(opGroup.Name)+"Client", buf.Bytes()) }
func (a *appGenerator) generateMain(app *GenApp) error { pth := filepath.Join(a.Target, "cmd", swag.ToCommandName(swag.ToGoName(app.Name)+"Server")) if fileExists(pth, "main") && !a.GenOpts.IncludeMain { log.Println("skipped (already exists) main template:", app.Package+".Main") return nil } buf := bytes.NewBuffer(nil) if err := mainTemplate.Execute(buf, app); err != nil { return err } log.Println("rendered main template:", "server."+swag.ToGoName(app.Name)) return writeToFile(pth, "main", buf.Bytes()) }
func (c *clientGenerator) generateResponses(op *GenOperation) error { buf := bytes.NewBuffer(nil) if err := clientResponseTemplate.Execute(buf, op); err != nil { return err } log.Println("rendered client responses template:", op.Package+"."+swag.ToGoName(op.Name)+"Responses") fp := filepath.Join(c.Target, c.ClientPackage) if len(op.Package) > 0 { fp = filepath.Join(fp, op.Package) } return writeToFile(fp, swag.ToGoName(op.Name)+"Responses", buf.Bytes()) }
func (a *appGenerator) generateConfigureAPI(app *GenApp) error { pth := filepath.Join(a.Target, app.APIPackage) nm := "Configure" + swag.ToGoName(app.Name) if fileExists(pth, nm) { log.Println("skipped (already exists) configure api template:", app.Package+".Configure"+swag.ToGoName(app.Name)) return nil } buf := bytes.NewBuffer(nil) if err := configureAPITemplate.Execute(buf, app); err != nil { return err } log.Println("rendered configure api template:", app.Package+".Configure"+swag.ToGoName(app.Name)) return writeToFileIfNotExist(pth, nm, buf.Bytes()) }
func (sg *schemaGenContext) NewAdditionalItems(schema *spec.Schema) *schemaGenContext { if Debug { log.Printf("new additional items\n") } 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 }
func TestSchemaValidation_RequiredProps(t *testing.T) { specDoc, err := loads.Spec("../fixtures/codegen/todolist.schemavalidation.yml") if assert.NoError(t, err) { k := "RequiredProps" schema := specDoc.Spec().Definitions[k] gm, err := makeGenDefinition(k, "models", schema, specDoc, true, true) 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) } } } } } } }
func discriminatorInfo(doc *analysis.Spec) *discInfo { baseTypes := make(map[string]discor) for _, sch := range doc.AllDefinitions() { if sch.Schema.Discriminator != "" { tpe, _ := sch.Schema.Extensions.GetString("x-go-name") if tpe == "" { tpe = swag.ToGoName(sch.Name) } baseTypes[sch.Ref.String()] = discor{ FieldName: sch.Schema.Discriminator, GoType: tpe, JSONName: sch.Name, } } } subTypes := make(map[string]discee) for _, sch := range doc.SchemasWithAllOf() { for _, ao := range sch.Schema.AllOf { if ao.Ref.String() != "" { if bt, ok := baseTypes[ao.Ref.String()]; ok { name, _ := sch.Schema.Extensions.GetString("x-class") if name == "" { name = sch.Name } tpe, _ := sch.Schema.Extensions.GetString("x-go-name") if tpe == "" { tpe = swag.ToGoName(sch.Name) } dce := discee{ FieldName: bt.FieldName, FieldValue: name, Ref: sch.Ref, ParentRef: ao.Ref, JSONName: sch.Name, GoType: tpe, } subTypes[sch.Ref.String()] = dce bt.Children = append(bt.Children, dce) baseTypes[ao.Ref.String()] = bt } } } } return &discInfo{Discriminators: baseTypes, Discriminated: subTypes} }
func (a *appGenerator) generateEmbeddedSwaggerJSON(app *GenApp) error { buf := bytes.NewBuffer(nil) appc := *app appc.Package = app.APIPackage if err := embeddedSpecTemplate.Execute(buf, &appc); err != nil { return err } log.Println("rendered embedded Swagger JSON template:", app.APIPackage+"."+swag.ToGoName(app.Name)) return writeToFile(filepath.Join(a.Target, a.ServerPackage), "embedded_spec", buf.Bytes()) }
func appNameOrDefault(specDoc *loads.Document, name, defaultName string) string { if strings.TrimSpace(name) == "" { if specDoc.Spec().Info != nil && strings.TrimSpace(specDoc.Spec().Info.Title) != "" { name = specDoc.Spec().Info.Title } else { name = defaultName } } return strings.TrimSuffix(swag.ToGoName(name), "API") }
func (sg *schemaGenContext) makeNewStruct(name string, schema spec.Schema) *schemaGenContext { if Debug { log.Println("making new struct", name, sg.Container) } sp := sg.TypeResolver.Doc.Spec() name = swag.ToGoName(name) if sg.TypeResolver.ModelName != sg.Name { name = swag.ToGoName(sg.TypeResolver.ModelName + " " + name) } if sp.Definitions == nil { sp.Definitions = make(spec.Definitions) } sp.Definitions[name] = schema pg := schemaGenContext{ Path: "", Name: name, Receiver: sg.Receiver, IndexVar: "i", ValueExpr: sg.Receiver, Schema: schema, Required: false, Named: true, ExtraSchemas: make(map[string]GenSchema), Discrimination: sg.Discrimination, Container: sg.Container, IncludeValidator: sg.IncludeValidator, IncludeModel: sg.IncludeModel, } if schema.Ref.String() == "" { resolver := newTypeResolver(sg.TypeResolver.ModelsPackage, sg.TypeResolver.Doc) resolver.ModelName = name //sg.TypeResolver.ModelName pg.TypeResolver = resolver } pg.GenSchema.IsVirtual = true sg.ExtraSchemas[name] = pg.GenSchema return &pg }
func (o *opGen) generateResponses() error { buf := bytes.NewBuffer(nil) if err := responsesTemplate.Execute(buf, o.data); err != nil { return err } log.Println("rendered responses template:", o.pkg+"."+o.cname+"Responses") fp := filepath.Join(o.Target, o.pkg) if o.pkg != o.APIPackage { fp = filepath.Join(o.Target, o.APIPackage, o.pkg) } return writeToFile(fp, swag.ToGoName(o.data.Name)+"Responses", buf.Bytes()) }
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 gatherOperations(specDoc *analysis.Spec, operationIDs []string) map[string]opRef { var oprefs opRefs for method, pathItem := range specDoc.Operations() { for path, operation := range pathItem { // nm := ensureUniqueName(operation.ID, method, path, operations) vv := *operation oprefs = append(oprefs, opRef{ Key: swag.ToGoName(strings.ToLower(method) + " " + path), Method: method, Path: path, ID: vv.ID, Op: &vv, }) } } sort.Sort(oprefs) operations := make(map[string]opRef) for _, opr := range oprefs { nm := opr.ID if nm == "" { nm = opr.Key } _, found := operations[nm] if found { 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 (b *codeGenOpBuilder) MakeParameter(receiver string, resolver *typeResolver, param spec.Parameter) (GenParameter, error) { if Debug { log.Printf("[%s %s] making parameter %q", b.Method, b.Path, param.Name) } if param.Ref.String() != "" { param2, err := spec.ResolveParameter(b.Doc.Spec(), param.Ref) if err != nil { return GenParameter{}, err } if param2 == nil { return GenParameter{}, fmt.Errorf("could not resolve parameter ref: %s", param.Ref.String()) } param = *param2 } var child *GenItems res := GenParameter{ Name: param.Name, ModelsPackage: b.ModelsPackage, Path: fmt.Sprintf("%q", param.Name), ValueExpression: fmt.Sprintf("%s.%s", receiver, pascalize(param.Name)), IndexVar: "i", BodyParam: nil, Default: param.Default, HasDefault: param.Default != nil, Enum: param.Enum, Description: param.Description, ReceiverName: receiver, CollectionFormat: param.CollectionFormat, Child: child, Location: param.In, AllowEmptyValue: (param.In == "query" || param.In == "formData") && param.AllowEmptyValue, } 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, IncludeModel: true, IncludeValidator: true, 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 len(schema.Properties) > 0 { if b.ExtraSchemas == nil { b.ExtraSchemas = make(map[string]GenSchema) } b.ExtraSchemas[nm] = schema } prevSchema := schema schema = GenSchema{} schema.IsAnonymous = false schema.GoType = nm schema.SwaggerType = nm if len(prevSchema.Properties) == 0 { schema.GoType = "interface{}" } schema.IsComplexObject = true schema.IsInterface = len(schema.Properties) == 0 } res.Schema = &schema it := res.Schema.Items items := new(GenItems) var prev *GenItems next := items for it != nil { next.resolvedType = it.resolvedType next.sharedValidations = it.sharedValidations next.Formatter = stringFormatters[it.SwaggerFormat] _, next.IsCustomFormatter = customFormatters[it.SwaggerFormat] it = it.Items if prev != nil { prev.Child = next } prev = next next = new(GenItems) } res.Child = items res.resolvedType = schema.resolvedType res.sharedValidations = schema.sharedValidations res.ZeroValue = schema.Zero() } 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.Name+"I", param.In, resolver, param.Items, nil) if err != nil { return GenParameter{}, err } res.Child = &pi } res.IsNullable = !param.Required && !param.AllowEmptyValue } 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 }
"schemaType": true, "subTypeBody": true, "schema": true, "additionalPropertiesSerializer": true, "serverDoc": true, "structfield": true, "hasDiscriminatedSerializer": true, "discriminatedSerializer": true, } // FuncMap is a map with default functions for use n the templates. // These are available in every template var FuncMap template.FuncMap = map[string]interface{}{ "pascalize": func(arg string) string { if len(arg) == 0 || arg[0] > '9' { return swag.ToGoName(arg) } return swag.ToGoName("Nr " + arg) }, "camelize": swag.ToJSONName, "varname": swag.ToVarName, "humanize": swag.ToHumanNameLower, "snakize": swag.ToFileName, "dasherize": swag.ToCommandName, "pluralizeFirstWord": func(arg string) string { sentence := strings.Split(arg, " ") if len(sentence) == 1 { return inflect.Pluralize(arg) }
func fieldNameFromParam(param *spec.Parameter) string { if nm, ok := param.Extensions.GetString("go-name"); ok { return nm } return swag.ToGoName(param.Name) }
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 } if _, ok := primitives[gp.GoType]; ok { if !assert.True(t, gp.IsPrimitive) { return false } } else { if !assert.False(t, gp.IsPrimitive) { 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 }
func (sg *schemaGenContext) buildAdditionalProperties() error { if sg.Schema.AdditionalProperties == nil { return nil } addp := *sg.Schema.AdditionalProperties wantsAdditional := addp.Allows || addp.Schema != nil sg.GenSchema.HasAdditionalProperties = wantsAdditional if !wantsAdditional { return nil } // flag swap if sg.GenSchema.IsComplexObject { sg.GenSchema.IsAdditionalProperties = true sg.GenSchema.IsComplexObject = false sg.GenSchema.IsMap = false } if addp.Schema == nil { return nil } if !sg.GenSchema.IsMap && (sg.GenSchema.IsAdditionalProperties && sg.Named) { sg.GenSchema.ValueExpression += "." + swag.ToGoName(sg.GenSchema.Name) comprop := sg.NewAdditionalProperty(*addp.Schema) comprop.Required = true if err := comprop.makeGenSchema(); err != nil { return err } sg.MergeResult(comprop, false) sg.GenSchema.AdditionalProperties = &comprop.GenSchema return nil } if sg.GenSchema.IsMap && wantsAdditional { // find out how deep this rabbit hole goes // descend, unwind and rewrite // This needs to be depth first, so it first goes as deep as it can and then // builds the result in reverse order. _, ls, err := newMapStack(sg) if err != nil { return err } if err := ls.Build(); err != nil { return err } return nil } if sg.GenSchema.IsAdditionalProperties && !sg.Named { // for an anonoymous object, first build the new object // and then replace the current one with a $ref to the // new object newObj := sg.makeNewStruct(sg.GenSchema.Name+" P"+strconv.Itoa(sg.Index), sg.Schema) if err := newObj.makeGenSchema(); err != nil { return err } sg.GenSchema = GenSchema{} sg.Schema = *spec.RefProperty("#/definitions/" + newObj.Name) if err := sg.makeGenSchema(); err != nil { return err } sg.MergeResult(newObj, false) sg.GenSchema.HasValidations = newObj.GenSchema.HasValidations sg.ExtraSchemas[newObj.Name] = newObj.GenSchema return nil } return nil }
func (sg *schemaGenContext) buildProperties() error { if Debug { log.Printf("building properties %s (parent: %s)", sg.Name, sg.Container) } //var discriminatorField string //if sg.Discrimination != nil { //dis, ok := sg.Discriminated["#/definitions/"+sg.Container] //if ok { //} //} for k, v := range sg.Schema.Properties { if Debug { bbb, _ := json.MarshalIndent(sg.Schema, "", " ") log.Printf("building property %s[%q] (tup: %t) %s\n", sg.Name, k, sg.IsTuple, bbb) } // check if this requires de-anonymizing, if so lift this as a new struct and extra schema tpe, err := sg.TypeResolver.ResolveSchema(&v, true, sg.IsTuple || containsString(sg.Schema.Required, k)) if sg.Schema.Discriminator == k { tpe.IsNullable = false } if err != nil { return err } vv := v var hasValidation bool var needsValidation bool if tpe.IsComplexObject && tpe.IsAnonymous && len(v.Properties) > 0 { pg := sg.makeNewStruct(sg.Name+swag.ToGoName(k), v) pg.IsTuple = sg.IsTuple if sg.Path != "" { pg.Path = sg.Path + "+ \".\"+" + fmt.Sprintf("%q", k) } else { pg.Path = fmt.Sprintf("%q", k) } if err := pg.makeGenSchema(); err != nil { return err } if v.Discriminator != "" { pg.GenSchema.IsBaseType = true pg.GenSchema.IsExported = true pg.GenSchema.HasBaseType = true } vv = *spec.RefProperty("#/definitions/" + pg.Name) hasValidation = pg.GenSchema.HasValidations needsValidation = pg.GenSchema.NeedsValidation sg.MergeResult(pg, false) sg.ExtraSchemas[pg.Name] = pg.GenSchema } emprop := sg.NewStructBranch(k, vv) emprop.IsTuple = sg.IsTuple if err := emprop.makeGenSchema(); err != nil { return err } if hasValidation || emprop.GenSchema.HasValidations { emprop.GenSchema.HasValidations = true sg.GenSchema.HasValidations = true } if needsValidation || emprop.GenSchema.NeedsValidation { emprop.GenSchema.NeedsValidation = true sg.GenSchema.NeedsValidation = true } if emprop.Schema.Ref.String() != "" { ref := emprop.Schema.Ref var sch *spec.Schema for ref.String() != "" { rsch, err := spec.ResolveRef(sg.TypeResolver.Doc.Spec(), &ref) if err != nil { return err } ref = rsch.Ref if rsch != nil && rsch.Ref.String() != "" { ref = rsch.Ref continue } ref = spec.Ref{} sch = rsch } if emprop.Discrimination != nil { if _, ok := emprop.Discrimination.Discriminators[emprop.Schema.Ref.String()]; ok { emprop.GenSchema.IsBaseType = true emprop.GenSchema.IsNullable = false emprop.GenSchema.HasBaseType = true } if _, ok := emprop.Discrimination.Discriminated[emprop.Schema.Ref.String()]; ok { emprop.GenSchema.IsSubType = true } } var nm = filepath.Base(emprop.Schema.Ref.GetURL().Fragment) var tn string if gn, ok := emprop.Schema.Extensions["x-go-name"]; ok { tn = gn.(string) nm = tn } else { tn = swag.ToGoName(nm) } tr := newTypeResolver(sg.TypeResolver.ModelsPackage, sg.TypeResolver.Doc) tr.ModelName = tn ttpe, err := tr.ResolveSchema(sch, false, true) if err != nil { return err } if ttpe.IsAliased { emprop.GenSchema.IsAliased = true } nv, hv := hasValidations(sch, false) if hv { emprop.GenSchema.HasValidations = true } if nv { emprop.GenSchema.NeedsValidation = true } } if sg.Schema.Discriminator == k { emprop.GenSchema.IsNullable = false } if emprop.GenSchema.IsBaseType { sg.GenSchema.HasBaseType = true } sg.MergeResult(emprop, false) sg.GenSchema.Properties = append(sg.GenSchema.Properties, emprop.GenSchema) } sort.Sort(sg.GenSchema.Properties) return nil }
func (a *appGenerator) Generate() error { app, err := a.makeCodegenApp() if err != nil { return err } if a.DumpData { bb, err := json.MarshalIndent(app, "", " ") if err != nil { return err } fmt.Fprintln(os.Stdout, string(bb)) return nil } errChan := make(chan error, 100) wg := nsync.NewControlWaitGroup(20) if a.GenOpts.IncludeModel { log.Printf("rendering %d models", len(app.Models)) for _, mod := range app.Models { if len(errChan) > 0 { wg.Wait() return <-errChan } modCopy := mod wg.Do(func() { modCopy.IncludeValidator = true // a.GenOpts.IncludeValidator modCopy.IncludeModel = true gen := &definitionGenerator{ Name: modCopy.Name, SpecDoc: a.SpecDoc, Target: filepath.Join(a.Target, a.ModelsPackage), Data: &modCopy, IncludeModel: true, IncludeStruct: true, IncludeValidator: true, } if err := gen.generateModel(); err != nil { errChan <- err } }) } } wg.Wait() if a.GenOpts.IncludeHandler { for _, opg := range app.OperationGroups { opgCopy := opg for _, op := range opgCopy.Operations { if len(errChan) > 0 { wg.Wait() return <-errChan } opCopy := op wg.Do(func() { gen := &opGen{ data: &opCopy, pkg: opgCopy.Name, cname: swag.ToGoName(opCopy.Name), IncludeHandler: a.GenOpts.IncludeHandler, IncludeParameters: a.GenOpts.IncludeParameters, IncludeResponses: a.GenOpts.IncludeResponses, Doc: a.SpecDoc, Analyzed: a.Analyzed, Target: filepath.Join(a.Target, a.ServerPackage), APIPackage: a.APIPackage, } if err := gen.Generate(); err != nil { errChan <- err } }) } } } if a.GenOpts.IncludeSupport { wg.Do(func() { if err := a.GenerateSupport(&app); err != nil { errChan <- err } }) } wg.Wait() if len(errChan) > 0 { return <-errChan } return nil }
func TestGenerateModel_Discriminators(t *testing.T) { specDoc, err := loads.Spec("../fixtures/codegen/todolist.discriminators.yml") if assert.NoError(t, err) { definitions := specDoc.Spec().Definitions for _, k := range []string{"cat", "Dog"} { schema := definitions[k] genModel, err := makeGenDefinition(k, "models", schema, specDoc, true, true) if assert.NoError(t, err) { assert.True(t, genModel.IsComplexObject) assert.Equal(t, "petType", genModel.DiscriminatorField) assert.Equal(t, k, genModel.DiscriminatorValue) buf := bytes.NewBuffer(nil) err := modelTemplate.Execute(buf, genModel) if assert.NoError(t, err) { b, err := formatGoFile("discriminated.go", buf.Bytes()) if assert.NoError(t, err) { res := string(b) assertNotInCode(t, "m.Pet.Validate", res) assertInCode(t, "if err := m.validateName(formats); err != nil {", res) if k == "Dog" { assertInCode(t, "func (m *Dog) validatePackSize(formats strfmt.Registry) error {", res) assertInCode(t, "if err := m.validatePackSize(formats); err != nil {", res) assertInCode(t, "data.PackSize = m.PackSize", res) assertInCode(t, "validate.Required(\"packSize\", \"body\", m.PackSize)", res) } else { assertInCode(t, "func (m *Cat) validateHuntingSkill(formats strfmt.Registry) error {", res) assertInCode(t, "if err := m.validateHuntingSkill(formats); err != nil {", res) assertInCode(t, "if err := m.validateHuntingSkillEnum(\"huntingSkill\", \"body\", *m.HuntingSkill); err != nil {", res) assertInCode(t, "data.HuntingSkill = m.HuntingSkill", res) } assertInCode(t, "Name *string `json:\"name\"`", res) assertInCode(t, "PetType string `json:\"petType\"`", res) assertInCode(t, "data.Name = m.nameField", res) assertInCode(t, "data.PetType = \""+k+"\"", res) kk := swag.ToGoName(k) assertInCode(t, "func (m *"+kk+") Name() *string", res) assertInCode(t, "func (m *"+kk+") SetName(val *string)", res) assertInCode(t, "func (m *"+kk+") PetType() string", res) assertInCode(t, "func (m *"+kk+") SetPetType(val string)", res) assertInCode(t, "validate.Required(\"name\", \"body\", m.Name())", res) } } } } k := "Pet" schema := definitions[k] genModel, err := makeGenDefinition(k, "models", schema, specDoc, true, true) if assert.NoError(t, err) { assert.True(t, genModel.IsComplexObject) assert.Equal(t, "petType", genModel.DiscriminatorField) assert.Len(t, genModel.Discriminates, 2) assert.Len(t, genModel.ExtraSchemas, 0) assert.Equal(t, "Cat", genModel.Discriminates["cat"]) assert.Equal(t, "Dog", genModel.Discriminates["Dog"]) buf := bytes.NewBuffer(nil) err := modelTemplate.Execute(buf, genModel) if assert.NoError(t, err) { b, err := formatGoFile("with_discriminator.go", buf.Bytes()) if assert.NoError(t, err) { res := string(b) assertInCode(t, "type Pet interface {", res) assertInCode(t, "runtime.Validatable", res) assertInCode(t, "Name() *string", res) assertInCode(t, "SetName(*string)", res) assertInCode(t, "PetType() string", res) assertInCode(t, "SetPetType(string)", res) assertInCode(t, "UnmarshalPet(reader io.Reader, consumer runtime.Consumer) (Pet, error)", res) assertInCode(t, "PetType string `json:\"petType\"`", res) assertInCode(t, "validate.RequiredString(\"petType\"", res) assertInCode(t, "switch getType.PetType {", res) assertInCode(t, "var result Cat", res) assertInCode(t, "var result Dog", res) } } } } }
func (b *codeGenOpBuilder) MakeResponse(receiver, name string, isSuccess bool, resolver *typeResolver, code int, resp spec.Response) (GenResponse, error) { if Debug { log.Printf("[%s %s] making id %q", b.Method, b.Path, b.Operation.ID) } if resp.Ref.String() != "" { resp2, err := spec.ResolveResponse(b.Doc.Spec(), resp.Ref) if err != nil { return GenResponse{}, err } if resp2 == nil { return GenResponse{}, fmt.Errorf("could not resolve response ref: %s", resp.Ref.String()) } resp = *resp2 } res := GenResponse{ Package: b.APIPackage, ModelsPackage: b.ModelsPackage, ReceiverName: receiver, Name: name, Description: resp.Description, DefaultImports: nil, Imports: nil, IsSuccess: isSuccess, Code: code, Method: b.Method, Path: b.Path, } for hName, header := range resp.Headers { res.Headers = append(res.Headers, b.MakeHeader(receiver, hName, header)) } sort.Sort(res.Headers) 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), IncludeModel: true, IncludeValidator: true, } if err := sc.makeGenSchema(); err != nil { return GenResponse{}, err } for k, v := range sc.ExtraSchemas { if b.ExtraSchemas == nil { b.ExtraSchemas = make(map[string]GenSchema) } 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 = resolver.goTypeName(nm) schema.SwaggerType = nm } res.Schema = &schema } return res, nil }
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 GenOperations authed := len(o.SecurityRequirements) > 0 var bldr codeGenOpBuilder bldr.Name = o.Name bldr.Method = o.Method bldr.Path = o.Path bldr.ModelsPackage = o.ModelsPackage bldr.Principal = o.Principal bldr.Target = o.Target bldr.Operation = o.Operation bldr.Authed = authed bldr.Doc = o.Doc bldr.Analyzed = o.Analyzed bldr.DefaultScheme = o.DefaultScheme bldr.DefaultProduces = o.DefaultProduces bldr.DefaultImports = []string{filepath.ToSlash(filepath.Join(baseImport(o.Base), o.ModelsPackage))} bldr.RootAPIPackage = o.APIPackage bldr.WithContext = o.WithContext bldr.DefaultConsumes = o.DefaultConsumes for _, tag := range o.Operation.Tags { if len(o.Tags) == 0 { bldr.APIPackage = mangleName(swag.ToFileName(tag), o.APIPackage) op, err := bldr.MakeOperation() if err != nil { return err } operations = append(operations, op) continue } for _, ft := range o.Tags { if ft == tag { bldr.APIPackage = mangleName(swag.ToFileName(tag), o.APIPackage) 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) } sort.Sort(operations) for _, op := range operations { if o.DumpData { bb, _ := json.MarshalIndent(swag.ToDynamicJSON(op), "", " ") fmt.Fprintln(os.Stdout, string(bb)) continue } og := new(opGen) og.IncludeHandler = o.IncludeHandler og.IncludeParameters = o.IncludeParameters og.IncludeResponses = o.IncludeResponses og.data = &op og.pkg = op.Package og.cname = swag.ToGoName(op.Name) og.Doc = o.Doc og.Analyzed = o.Analyzed og.Target = o.Target og.APIPackage = o.APIPackage og.WithContext = o.WithContext return og.Generate() } return nil }