github.com/kaisawind/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  }