github.com/youyuanwu/go-swagger@v0.19.0/cmd/swagger/commands/serve.go (about) 1 package commands 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "log" 8 "net" 9 "net/http" 10 "net/url" 11 "path" 12 "strconv" 13 14 "github.com/go-openapi/loads" 15 "github.com/go-openapi/runtime/middleware" 16 "github.com/go-openapi/swag" 17 "github.com/gorilla/handlers" 18 "github.com/toqueteos/webbrowser" 19 ) 20 21 // ServeCmd to serve a swagger spec with docs ui 22 type ServeCmd struct { 23 BasePath string `long:"base-path" description:"the base path to serve the spec and UI at"` 24 Flavor string `short:"F" long:"flavor" description:"the flavor of docs, can be swagger or redoc" default:"redoc" choice:"redoc" choice:"swagger"` 25 DocURL string `long:"doc-url" description:"override the url which takes a url query param to render the doc ui"` 26 NoOpen bool `long:"no-open" description:"when present won't open the the browser to show the url"` 27 NoUI bool `long:"no-ui" description:"when present, only the swagger spec will be served"` 28 Port int `long:"port" short:"p" description:"the port to serve this site" env:"PORT"` 29 Host string `long:"host" description:"the interface to serve this site, defaults to 0.0.0.0" env:"HOST"` 30 } 31 32 // Execute the serve command 33 func (s *ServeCmd) Execute(args []string) error { 34 if len(args) == 0 { 35 return errors.New("specify the spec to serve as argument to the serve command") 36 } 37 38 specDoc, err := loads.Spec(args[0]) 39 if err != nil { 40 return err 41 } 42 b, err := json.MarshalIndent(specDoc.Spec(), "", " ") 43 if err != nil { 44 return err 45 } 46 47 basePath := s.BasePath 48 if basePath == "" { 49 basePath = "/" 50 } 51 52 listener, err := net.Listen("tcp4", net.JoinHostPort(s.Host, strconv.Itoa(s.Port))) 53 if err != nil { 54 return err 55 } 56 sh, sp, err := swag.SplitHostPort(listener.Addr().String()) 57 if err != nil { 58 return err 59 } 60 if sh == "0.0.0.0" { 61 sh = "localhost" 62 } 63 64 visit := s.DocURL 65 handler := http.NotFoundHandler() 66 if !s.NoUI { 67 if s.Flavor == "redoc" { 68 handler = middleware.Redoc(middleware.RedocOpts{ 69 BasePath: basePath, 70 SpecURL: path.Join(basePath, "swagger.json"), 71 Path: "docs", 72 }, handler) 73 visit = fmt.Sprintf("http://%s:%d%s", sh, sp, path.Join(basePath, "docs")) 74 } else if visit != "" || s.Flavor == "swagger" { 75 if visit == "" { 76 visit = "http://petstore.swagger.io/" 77 } 78 u, err := url.Parse(visit) 79 if err != nil { 80 return err 81 } 82 q := u.Query() 83 q.Add("url", fmt.Sprintf("http://%s:%d%s", sh, sp, path.Join(basePath, "swagger.json"))) 84 u.RawQuery = q.Encode() 85 visit = u.String() 86 } 87 } 88 89 handler = handlers.CORS()(middleware.Spec(basePath, b, handler)) 90 errFuture := make(chan error) 91 go func() { 92 docServer := new(http.Server) 93 docServer.SetKeepAlivesEnabled(true) 94 docServer.Handler = handler 95 96 errFuture <- docServer.Serve(listener) 97 }() 98 99 if !s.NoOpen && !s.NoUI { 100 err := webbrowser.Open(visit) 101 if err != nil { 102 return err 103 } 104 } 105 log.Println("serving docs at", visit) 106 return <-errFuture 107 }