func newMetaParser(swspec *spec.Swagger) *sectionedParser { sp := new(sectionedParser) if swspec.Info == nil { swspec.Info = new(spec.Info) } info := swspec.Info sp.setTitle = func(lines []string) { tosave := joinDropLast(lines) if len(tosave) > 0 { tosave = rxStripTitleComments.ReplaceAllString(tosave, "") } info.Title = tosave } sp.setDescription = func(lines []string) { info.Description = joinDropLast(lines) } sp.taggers = []tagParser{ newMultiLineTagParser("TOS", newMultilineDropEmptyParser(rxTOS, metaTOSSetter(info))), newMultiLineTagParser("Consumes", newMultilineDropEmptyParser(rxConsumes, metaConsumesSetter(swspec))), newMultiLineTagParser("Produces", newMultilineDropEmptyParser(rxProduces, metaProducesSetter(swspec))), newSingleLineTagParser("Schemes", newSetSchemes(metaSchemeSetter(swspec))), newSingleLineTagParser("SecurityDefinitions", newSetSecurityDefinitions(rxSecurity, metaSecuritySetter(swspec))), newSingleLineTagParser("Version", &setMetaSingle{swspec, rxVersion, setInfoVersion}), newSingleLineTagParser("Host", &setMetaSingle{swspec, rxHost, setSwaggerHost}), newSingleLineTagParser("BasePath", &setMetaSingle{swspec, rxBasePath, setSwaggerBasePath}), newSingleLineTagParser("Contact", &setMetaSingle{swspec, rxContact, setInfoContact}), newSingleLineTagParser("License", &setMetaSingle{swspec, rxLicense, setInfoLicense}), } return sp }
func setSwaggerBasePath(swspec *spec.Swagger, lines []string) error { var ln string if len(lines) > 0 { ln = lines[0] } swspec.BasePath = ln return nil }
func setSwaggerHost(swspec *spec.Swagger, lines []string) error { lns := lines if len(lns) == 0 || (len(lines) == 1 && len(lines[0]) == 0) { lns = []string{"localhost"} } swspec.Host = lns[0] return nil }
func newSpec(endpoint string) *spec.Swagger { // TODO enable defaults // TODO complete swagger metadata and move to diff function api := new(spec.Swagger) api.Swagger = "2.0" api.BasePath = endpoint api.Info = new(spec.Info) api.Info.Version = "0.0.0" api.Info.Title = revel.AppName api.Info.Description = "Description" api.Info.TermsOfService = "http://swagger.io/terms/" api.Info.Contact = new(spec.ContactInfo) api.Info.Contact.Name = "" api.Info.Contact.Email = "" api.Info.Contact.URL = "" api.Info.License = new(spec.License) api.Info.License.Name = "LICENSE" api.Info.License.URL = "URL" // Now is added on requests to Swaggify.Spec // TODO check if https is HSTS exclusively or no for revel // TODO ALSO this can be SSL terminated by proxy so this may need changing if revel.HttpSsl { api.Schemes = []string{"https"} } else { api.Schemes = []string{"http"} } api.Consumes = ContentTypes api.Produces = ContentTypes // the Swagger type hoists unexported types for some annoying reason api.Paths = buildPaths(api.BasePath) api.Definitions = buildDefinitions(api.BasePath) return api }
// newAppScanner creates a new api parser func newAppScanner(bp string, input *spec.Swagger, includes, excludes packageFilters) (*appScanner, error) { var ldr loader.Config ldr.ParserMode = goparser.ParseComments ldr.ImportWithTests(bp) prog, err := ldr.Load() if err != nil { return nil, err } if input == nil { input = new(spec.Swagger) input.Swagger = "2.0" } if input.Paths == nil { input.Paths = new(spec.Paths) } if input.Definitions == nil { input.Definitions = make(map[string]spec.Schema) } if input.Responses == nil { input.Responses = make(map[string]spec.Response) } return &appScanner{ MainPackage: bp, prog: prog, input: input, loader: &ldr, operations: collectOperationsFromInput(input), definitions: input.Definitions, responses: input.Responses, classifier: &programClassifier{ Includes: includes, Excludes: excludes, }, }, nil }
func metaSecuritySetter(meta *spec.Swagger) func([]map[string][]string) { return func(secDefs []map[string][]string) { meta.Security = secDefs } }
func metaSchemeSetter(meta *spec.Swagger) func([]string) { return func(schemes []string) { meta.Schemes = schemes } }
func metaProducesSetter(meta *spec.Swagger) func([]string) { return func(produces []string) { meta.Produces = produces } }
func metaConsumesSetter(meta *spec.Swagger) func([]string) { return func(consumes []string) { meta.Consumes = consumes } }
func safeInfo(swspec *spec.Swagger) *spec.Info { if swspec.Info == nil { swspec.Info = new(spec.Info) } return swspec.Info }
func (g *Generator) generateSwagger() (*spec.Swagger, error) { contact := &spec.ContactInfo{ Name: "API Support", URL: "api-suport.url", Email: "*****@*****.**", } license := &spec.License{ Name: "APACHE-2.0", URL: "url://to/license", } info := new(spec.Info) info.Description = "API description" info.Title = "API title" info.TermsOfService = "url://to/tos" info.Contact = contact info.License = license info.Version = "v1" sw := new(spec.Swagger) sw.Swagger = "2.0" sw.Info = info // sw.Consumes = []string{"application/x-www-form-urlencoded", "application/json", "application/x-protobuf"} // sw.Produces = []string{"application/json", "application/x-protobuf"} // TODO(ceram1): Make this configurable. sw.BasePath = "/api/" sw.Host = "authagain.appspot.com" sw.Paths = new(spec.Paths) sw.Paths.Paths = make(map[string]spec.PathItem) sw.Definitions = make(map[string]spec.Schema) sw.Schemes = []string{"https", "http"} for _, svc := range g.file.Services { info.Title = svc.GetName() + " API" if cmt := g.file.GetCommentText(svc.CommentPath); cmt != nil { info.Description = *cmt } for _, mtd := range svc.Methods { for _, b := range mtd.Bindings { var p *spec.PathItem path := buildPath(b.PathTmpl) if pi, ok := sw.Paths.Paths[path]; !ok { p = new(spec.PathItem) } else { p = &pi } op := g.generateOperation(b) if b.HTTPMethod == "GET" { p.Get = op } else if b.HTTPMethod == "POST" { p.Post = op } else if b.HTTPMethod == "PUT" { p.Put = op } else if b.HTTPMethod == "DELETE" { p.Delete = op } else { return nil, fmt.Errorf("Unknown http method `%v`", b.HTTPMethod) } sw.Paths.Paths[path] = *p } } } for _, msg := range g.file.Messages { def := g.generateDefinition(msg) sw.Definitions[def.Title] = *def } sw.Info = info return sw, nil }
// Execute this command func (s *Spec) Execute(args []string) error { targetPath := "." if len(args) > 0 { targetPath = args[0] } realPath, err := filepath.Abs(targetPath) if err != nil { return err } var file *os.File switch s.Format { case "json": file, err = os.Create(filepath.Join(realPath, "swagger.json")) if err != nil { return err } case "yaml", "yml": file, err = os.Create(filepath.Join(realPath, "swagger.yml")) if err != nil { return err } default: return fmt.Errorf("invalid format: %s", s.Format) } defer file.Close() log.Println("creating specification document in", filepath.Join(targetPath, file.Name())) var doc spec.Swagger info := new(spec.Info) doc.Info = info doc.Swagger = "2.0" doc.Paths = new(spec.Paths) doc.Definitions = make(spec.Definitions) info.Title = s.Title if info.Title == "" { info.Title = swag.ToHumanNameTitle(filepath.Base(realPath)) } info.Description = s.Description info.Version = s.Version info.TermsOfService = s.Terms if s.Contact.Name != "" || s.Contact.Email != "" || s.Contact.URL != "" { var contact spec.ContactInfo contact.Name = s.Contact.Name contact.Email = s.Contact.Email contact.URL = s.Contact.URL info.Contact = &contact } if s.License.Name != "" || s.License.URL != "" { var license spec.License license.Name = s.License.Name license.URL = s.License.URL info.License = &license } for _, cons := range s.Consumes { doc.Consumes = append(doc.Consumes, cons) } for _, prods := range s.Produces { doc.Produces = append(doc.Produces, prods) } for _, scheme := range s.Schemes { doc.Schemes = append(doc.Schemes, scheme) } if s.Format == "json" { enc := json.NewEncoder(file) if err := enc.Encode(doc); err != nil { return err } return nil } b, err := yaml.Marshal(swag.ToDynamicJSON(doc)) if err != nil { return err } if _, err := file.Write(b); err != nil { return err } return nil }