Exemple #1
0
// GenerateClient generates a client library for a swagger spec document.
func GenerateClient(name string, modelNames, operationIDs []string, opts GenOpts) error {
	// Load the spec
	_, specDoc, err := loadSpec(opts.Spec)
	if err != nil {
		return err
	}

	models := gatherModels(specDoc, modelNames)
	operations := gatherOperations(specDoc, operationIDs)

	defaultScheme := opts.DefaultScheme
	if defaultScheme == "" {
		defaultScheme = "http"
	}

	generator := appGenerator{
		Name:          appNameOrDefault(specDoc, name, "swagger"),
		SpecDoc:       specDoc,
		Models:        models,
		Operations:    operations,
		Target:        opts.Target,
		DumpData:      opts.DumpData,
		Package:       mangleName(swag.ToFileName(opts.APIPackage), "api"),
		APIPackage:    mangleName(swag.ToFileName(opts.APIPackage), "api"),
		ModelsPackage: mangleName(swag.ToFileName(opts.ModelPackage), "definitions"),
		ServerPackage: mangleName(swag.ToFileName(opts.ServerPackage), "server"),
		ClientPackage: mangleName(swag.ToFileName(opts.ClientPackage), "client"),
		Principal:     opts.Principal,
		DefaultScheme: defaultScheme,
	}
	generator.Receiver = "o"

	return (&clientGenerator{generator}).Generate()
}
// GenerateServerOperation generates a parameter model, parameter validator, http handler implementations for a given operation
// It also generates an operation handler interface that uses the parameter model for handling a valid request.
// Allows for specifying a list of tags to include only certain tags for the generation
func GenerateServerOperation(operationNames, tags []string, includeHandler, includeParameters, includeResponses bool, opts GenOpts) error {

	if opts.TemplateDir != "" {
		if err := templates.LoadDir(opts.TemplateDir); err != nil {
			return err
		}
	}

	compileTemplates()

	// Load the spec
	_, specDoc, err := loadSpec(opts.Spec)
	if err != nil {
		return err
	}

	ops := gatherOperations(specDoc, operationNames)

	for operationName, opRef := range ops {
		method, path, operation := opRef.Method, opRef.Path, opRef.Op
		defaultScheme := opts.DefaultScheme
		if defaultScheme == "" {
			defaultScheme = "http"
		}
		defaultProduces := opts.DefaultProduces
		if defaultProduces == "" {
			defaultProduces = "application/json"
		}

		apiPackage := mangleName(swag.ToFileName(opts.APIPackage), "api")
		serverPackage := mangleName(swag.ToFileName(opts.ServerPackage), "server")
		generator := operationGenerator{
			Name:                 operationName,
			Method:               method,
			Path:                 path,
			APIPackage:           apiPackage,
			ModelsPackage:        mangleName(swag.ToFileName(opts.ModelPackage), "definitions"),
			ClientPackage:        mangleName(swag.ToFileName(opts.ClientPackage), "client"),
			ServerPackage:        serverPackage,
			Operation:            *operation,
			SecurityRequirements: specDoc.SecurityRequirementsFor(operation),
			Principal:            opts.Principal,
			Target:               filepath.Join(opts.Target, serverPackage),
			Base:                 opts.Target,
			Tags:                 tags,
			IncludeHandler:       includeHandler,
			IncludeParameters:    includeParameters,
			IncludeResponses:     includeResponses,
			DumpData:             opts.DumpData,
			DefaultScheme:        defaultScheme,
			DefaultProduces:      defaultProduces,
			Doc:                  specDoc,
		}
		if err := generator.Generate(); err != nil {
			return err
		}
	}
	return nil
}
Exemple #3
0
func newAppGenerator(name string, modelNames, operationIDs []string, opts *GenOpts) (*appGenerator, error) {

	if opts.TemplateDir != "" {
		if err := templates.LoadDir(opts.TemplateDir); err != nil {
			return nil, err
		}
	}

	compileTemplates()

	// Load the spec
	_, specDoc, err := loadSpec(opts.Spec)
	if err != nil {
		return nil, err
	}

	models, err := gatherModels(specDoc, modelNames)
	if err != nil {
		return nil, err
	}
	operations := gatherOperations(specDoc, operationIDs)
	if len(operations) == 0 {
		return nil, errors.New("no operations were selected")
	}

	defaultScheme := opts.DefaultScheme
	if defaultScheme == "" {
		defaultScheme = "http"
	}
	defaultProduces := opts.DefaultProduces
	if defaultProduces == "" {
		defaultProduces = "application/json"
	}

	apiPackage := mangleName(swag.ToFileName(opts.APIPackage), "api")
	return &appGenerator{
		Name:       appNameOrDefault(specDoc, name, "swagger"),
		Receiver:   "o",
		SpecDoc:    specDoc,
		Models:     models,
		Operations: operations,
		Target:     opts.Target,
		// Package:       filepath.Base(opts.Target),
		DumpData:        opts.DumpData,
		Package:         apiPackage,
		APIPackage:      apiPackage,
		ModelsPackage:   mangleName(swag.ToFileName(opts.ModelPackage), "definitions"),
		ServerPackage:   mangleName(swag.ToFileName(opts.ServerPackage), "server"),
		ClientPackage:   mangleName(swag.ToFileName(opts.ClientPackage), "client"),
		Principal:       opts.Principal,
		DefaultScheme:   defaultScheme,
		DefaultProduces: defaultProduces,
		GenOpts:         opts,
	}, nil
}
Exemple #4
0
// GenerateServerOperation generates a parameter model, parameter validator, http handler implementations for a given operation
// It also generates an operation handler interface that uses the parameter model for handling a valid request.
// Allows for specifying a list of tags to include only certain tags for the generation
func GenerateServerOperation(operationNames, tags []string, includeHandler, includeParameters, includeResponses bool, opts GenOpts) error {
	// Load the spec
	specPath, specDoc, err := loadSpec(opts.Spec)
	if err != nil {
		return err
	}

	if len(operationNames) == 0 {
		operationNames = specDoc.OperationIDs()
	}

	for _, operationName := range operationNames {
		method, path, operation, ok := specDoc.OperationForName(operationName)
		if !ok {
			return fmt.Errorf("operation %q not found in %s", operationName, specPath)
		}
		defaultScheme := opts.DefaultScheme
		if defaultScheme == "" {
			defaultScheme = "http"
		}

		apiPackage := mangleName(swag.ToFileName(opts.APIPackage), "api")
		serverPackage := mangleName(swag.ToFileName(opts.ServerPackage), "server")
		generator := operationGenerator{
			Name:                 operationName,
			Method:               method,
			Path:                 path,
			APIPackage:           apiPackage,
			ModelsPackage:        mangleName(swag.ToFileName(opts.ModelPackage), "definitions"),
			ClientPackage:        mangleName(swag.ToFileName(opts.ClientPackage), "client"),
			ServerPackage:        serverPackage,
			Operation:            *operation,
			SecurityRequirements: specDoc.SecurityRequirementsFor(operation),
			Principal:            opts.Principal,
			Target:               filepath.Join(opts.Target, serverPackage),
			Base:                 opts.Target,
			Tags:                 tags,
			IncludeHandler:       includeHandler,
			IncludeParameters:    includeParameters,
			IncludeResponses:     includeResponses,
			DumpData:             opts.DumpData,
			DefaultScheme:        defaultScheme,
			Doc:                  specDoc,
		}
		if err := generator.Generate(); err != nil {
			return err
		}
	}
	return nil
}
Exemple #5
0
func stripTestFromFileName(name string) string {
	ffn := swag.ToFileName(name)
	if strings.HasSuffix(ffn, "_test") {
		ffn = ffn[:len(ffn)-5]
	}
	return ffn
}
Exemple #6
0
func writeToFile(target, name string, content []byte) error {
	ffn := swag.ToFileName(name) + ".go"
	res, err := formatGoFile(ffn, content)
	if err != nil {
		log.Println(err)
		return writeFile(target, ffn, content)
	}

	return writeFile(target, ffn, res)
}
Exemple #7
0
// GenerateSupport generates the supporting files for an API
func GenerateSupport(name string, modelNames, operationIDs []string, opts GenOpts) error {
	// Load the spec
	_, specDoc, err := loadSpec(opts.Spec)
	if err != nil {
		return err
	}

	models := gatherModels(specDoc, modelNames)
	operations := gatherOperations(specDoc, operationIDs)
	if len(operations) == 0 {
		return errors.New("no operations were selected")
	}

	defaultScheme := opts.DefaultScheme
	if defaultScheme == "" {
		defaultScheme = "http"
	}

	apiPackage := mangleName(swag.ToFileName(opts.APIPackage), "api")
	generator := appGenerator{
		Name:       appNameOrDefault(specDoc, name, "swagger"),
		Receiver:   "o",
		SpecDoc:    specDoc,
		Models:     models,
		Operations: operations,
		Target:     opts.Target,
		// Package:       filepath.Base(opts.Target),
		DumpData:      opts.DumpData,
		Package:       apiPackage,
		APIPackage:    apiPackage,
		ModelsPackage: mangleName(swag.ToFileName(opts.ModelPackage), "definitions"),
		ServerPackage: mangleName(swag.ToFileName(opts.ServerPackage), "server"),
		ClientPackage: mangleName(swag.ToFileName(opts.ClientPackage), "client"),
		Principal:     opts.Principal,
		DefaultScheme: defaultScheme,
	}

	return generator.Generate()
}
Exemple #8
0
func writeToTestFile(target, name string, content []byte) error {
	ffn := swag.ToFileName(name)
	if !strings.HasSuffix(ffn, "_test") {
		ffn += "_test"
	}
	ffn += ".go"

	res, err := formatGoFile(filepath.Join(target, ffn), content)
	if err != nil {
		log.Println(err)
		return writeFile(target, ffn, content)
	}

	return writeFile(target, ffn, res)
}
Exemple #9
0
func mangleName(name, suffix string) string {
	if _, ok := reservedGoWordSet[swag.ToFileName(name)]; !ok {
		return name
	}
	return strings.Join([]string{name, suffix}, "_")
}
Exemple #10
0
func fileExists(target, name string) bool {
	ffn := swag.ToFileName(name) + ".go"
	_, err := os.Stat(filepath.Join(target, ffn))
	return !os.IsNotExist(err)
}
Exemple #11
0
func (a *appGenerator) makeCodegenApp() (GenApp, error) {
	sw := a.SpecDoc.Spec()
	receiver := a.Receiver

	var defaultImports []string

	jsonb, _ := json.MarshalIndent(sw, "", "  ")

	consumes, _ := a.makeConsumes()
	produces, _ := a.makeProduces()

	prin := a.Principal
	if prin == "" {
		prin = "interface{}"
	}
	security := a.makeSecuritySchemes()

	var genMods []GenDefinition
	importPath := filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ModelsPackage))
	defaultImports = append(defaultImports, importPath)

	for mn, m := range a.Models {
		mod, err := makeGenDefinition(
			mn,
			a.ModelsPackage,
			m,
			a.SpecDoc,
		)
		if err != nil {
			return GenApp{}, err
		}
		mod.ReceiverName = receiver
		genMods = append(genMods, *mod)
	}

	var genOps GenOperations
	tns := make(map[string]struct{})
	var bldr codeGenOpBuilder
	bldr.ModelsPackage = a.ModelsPackage
	bldr.Principal = prin
	bldr.Target = a.Target
	bldr.DefaultImports = defaultImports
	bldr.Doc = a.SpecDoc

	for on, o := range a.Operations {
		bldr.Name = on
		bldr.Operation = o
		bldr.Authed = len(a.SpecDoc.SecurityRequirementsFor(&o)) > 0
		ap := a.APIPackage
		if len(o.Tags) > 0 {
			for _, tag := range o.Tags {
				tns[tag] = struct{}{}
				bldr.APIPackage = swag.ToFileName(tag)
				op, err := bldr.MakeOperation()
				if err != nil {
					return GenApp{}, err
				}
				op.ReceiverName = receiver
				genOps = append(genOps, op)
			}
		} else {
			bldr.APIPackage = swag.ToFileName(ap)
			op, err := bldr.MakeOperation()
			if err != nil {
				return GenApp{}, err
			}
			op.ReceiverName = receiver
			genOps = append(genOps, op)
		}
	}
	for k := range tns {
		importPath := filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ServerPackage, a.APIPackage, k))
		defaultImports = append(defaultImports, importPath)
	}
	sort.Sort(genOps)

	defaultConsumes := "application/json"
	rc := a.SpecDoc.RequiredConsumes()
	if len(rc) > 0 {
		defaultConsumes = rc[0]
	}

	defaultProduces := "application/json"
	rp := a.SpecDoc.RequiredProduces()
	if len(rp) > 0 {
		defaultProduces = rp[0]
	}

	return GenApp{
		Package:             a.Package,
		ReceiverName:        receiver,
		Name:                a.Name,
		Host:                sw.Host,
		BasePath:            sw.BasePath,
		Schemes:             sw.Schemes,
		ExternalDocs:        sw.ExternalDocs,
		Info:                sw.Info,
		Consumes:            consumes,
		Produces:            produces,
		DefaultConsumes:     defaultConsumes,
		DefaultProduces:     defaultProduces,
		DefaultImports:      defaultImports,
		SecurityDefinitions: security,
		Models:              genMods,
		Operations:          genOps,
		Principal:           prin,
		SwaggerJSON:         fmt.Sprintf("%#v", jsonb),
	}, nil
}
Exemple #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 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.DefaultScheme = o.DefaultScheme
	bldr.DefaultImports = []string{filepath.ToSlash(filepath.Join(baseImport(o.Base), o.ModelsPackage))}

	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
		}
		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)
		}

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

		if o.IncludeResponses && len(op.Responses) > 0 {
			if err := o.generateResponses(); err != nil {
				return fmt.Errorf("responses: %s", err)
			}
			log.Println("generated responses", op.Package+"."+o.cname+"Responses")
		}

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

	return 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.DefaultScheme = o.DefaultScheme
	bldr.DefaultProduces = o.DefaultProduces
	bldr.DefaultImports = []string{filepath.ToSlash(filepath.Join(baseImport(o.Base), o.ModelsPackage))}
	bldr.RootAPIPackage = o.APIPackage

	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.Target = o.Target
		og.APIPackage = o.APIPackage
		return og.Generate()
	}

	return nil
}
Exemple #14
0
func (a *appGenerator) makeCodegenApp() (GenApp, error) {
	log.Println("building a plan for generation")
	sw := a.SpecDoc.Spec()
	receiver := a.Receiver

	var defaultImports []string

	jsonb, _ := json.MarshalIndent(sw, "", "  ")

	consumes, _ := a.makeConsumes()
	produces, _ := a.makeProduces()

	prin := a.Principal
	if prin == "" {
		prin = "interface{}"
	}
	security := a.makeSecuritySchemes()

	var genMods []GenDefinition
	importPath := filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ModelsPackage))
	defaultImports = append(defaultImports, importPath)

	log.Println("planning definitions")
	for mn, m := range a.Models {
		mod, err := makeGenDefinition(
			mn,
			a.ModelsPackage,
			m,
			a.SpecDoc,
		)
		if err != nil {
			return GenApp{}, err
		}
		//mod.ReceiverName = receiver
		genMods = append(genMods, *mod)
	}

	log.Println("planning operations")
	tns := make(map[string]struct{})
	var genOps GenOperations
	for on, opp := range a.Operations {
		o := opp.Op
		o.ID = on
		var bldr codeGenOpBuilder
		bldr.ModelsPackage = a.ModelsPackage
		bldr.Principal = prin
		bldr.Target = a.Target
		bldr.DefaultImports = defaultImports
		bldr.DefaultScheme = a.DefaultScheme
		bldr.Doc = &(*a.SpecDoc)
		// TODO: change operation name to something safe
		bldr.Name = on
		bldr.Operation = *o
		bldr.Method = opp.Method
		bldr.Path = opp.Path
		bldr.Authed = len(a.SpecDoc.SecurityRequirementsFor(o)) > 0
		ap := a.APIPackage
		bldr.RootAPIPackage = swag.ToFileName(a.APIPackage)
		if len(o.Tags) > 0 {
			for _, tag := range o.Tags {
				tns[tag] = struct{}{}
				bldr.APIPackage = mangleName(swag.ToFileName(tag), a.APIPackage)
				op, err := bldr.MakeOperation()
				if err != nil {
					return GenApp{}, err
				}
				op.ReceiverName = receiver
				genOps = append(genOps, op)
			}
		} else {
			bldr.APIPackage = swag.ToFileName(ap)
			op, err := bldr.MakeOperation()
			if err != nil {
				return GenApp{}, err
			}
			op.ReceiverName = receiver
			genOps = append(genOps, op)
		}
	}
	for k := range tns {
		importPath := filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ServerPackage, a.APIPackage, swag.ToFileName(k)))
		defaultImports = append(defaultImports, importPath)
	}
	sort.Sort(genOps)

	log.Println("grouping operations into packages")
	opsGroupedByTag := make(map[string]GenOperations)
	for _, operation := range genOps {
		if operation.Package == "" {
			operation.Package = a.Package
		}
		opsGroupedByTag[operation.Package] = append(opsGroupedByTag[operation.Package], operation)
	}

	var opGroups GenOperationGroups
	for k, v := range opsGroupedByTag {
		sort.Sort(v)
		opGroup := GenOperationGroup{
			Name:           k,
			Operations:     v,
			DefaultImports: []string{filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ModelsPackage))},
			RootPackage:    a.APIPackage,
		}
		opGroups = append(opGroups, opGroup)
		var importPath string
		if k == a.APIPackage {
			importPath = filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ServerPackage, a.APIPackage))
		} else {
			importPath = filepath.ToSlash(filepath.Join(baseImport(a.Target), a.ServerPackage, a.APIPackage, k))
		}
		defaultImports = append(defaultImports, importPath)
	}
	sort.Sort(opGroups)

	log.Println("planning meta data and facades")
	defaultConsumes := "application/json"
	rc := a.SpecDoc.RequiredConsumes()
	if len(rc) > 0 {
		defaultConsumes = rc[0]
	}

	defaultProduces := "application/json"
	rp := a.SpecDoc.RequiredProduces()
	if len(rp) > 0 {
		defaultProduces = rp[0]
	}

	var collectedSchemes []string
	var extraSchemes []string
	for _, op := range genOps {
		collectedSchemes = concatUnique(collectedSchemes, op.Schemes)
		extraSchemes = concatUnique(extraSchemes, op.ExtraSchemes)
	}

	host := "localhost"
	if sw.Host != "" {
		host = sw.Host
	}

	basePath := "/"
	if sw.BasePath != "" {
		basePath = "/"
	}

	return GenApp{
		Package:             a.Package,
		ReceiverName:        receiver,
		Name:                a.Name,
		Host:                host,
		BasePath:            basePath,
		Schemes:             schemeOrDefault(collectedSchemes, a.DefaultScheme),
		ExtraSchemes:        extraSchemes,
		ExternalDocs:        sw.ExternalDocs,
		Info:                sw.Info,
		Consumes:            consumes,
		Produces:            produces,
		DefaultConsumes:     defaultConsumes,
		DefaultProduces:     defaultProduces,
		DefaultImports:      defaultImports,
		SecurityDefinitions: security,
		Models:              genMods,
		Operations:          genOps,
		OperationGroups:     opGroups,
		Principal:           prin,
		SwaggerJSON:         fmt.Sprintf("%#v", jsonb),
	}, nil
}