...

Source file src/github.com/go-openapi/runtime/middleware/ui_options.go

Documentation: github.com/go-openapi/runtime/middleware

     1  package middleware
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/gob"
     6  	"fmt"
     7  	"net/http"
     8  	"path"
     9  	"strings"
    10  )
    11  
    12  const (
    13  	// constants that are common to all UI-serving middlewares
    14  	defaultDocsPath  = "docs"
    15  	defaultDocsURL   = "/swagger.json"
    16  	defaultDocsTitle = "API Documentation"
    17  )
    18  
    19  // uiOptions defines common options for UI serving middlewares.
    20  type uiOptions struct {
    21  	// BasePath for the UI, defaults to: /
    22  	BasePath string
    23  
    24  	// Path combines with BasePath to construct the path to the UI, defaults to: "docs".
    25  	Path string
    26  
    27  	// SpecURL is the URL of the spec document.
    28  	//
    29  	// Defaults to: /swagger.json
    30  	SpecURL string
    31  
    32  	// Title for the documentation site, default to: API documentation
    33  	Title string
    34  
    35  	// Template specifies a custom template to serve the UI
    36  	Template string
    37  }
    38  
    39  // toCommonUIOptions converts any UI option type to retain the common options.
    40  //
    41  // This uses gob encoding/decoding to convert common fields from one struct to another.
    42  func toCommonUIOptions(opts interface{}) uiOptions {
    43  	var buf bytes.Buffer
    44  	enc := gob.NewEncoder(&buf)
    45  	dec := gob.NewDecoder(&buf)
    46  	var o uiOptions
    47  	err := enc.Encode(opts)
    48  	if err != nil {
    49  		panic(err)
    50  	}
    51  
    52  	err = dec.Decode(&o)
    53  	if err != nil {
    54  		panic(err)
    55  	}
    56  
    57  	return o
    58  }
    59  
    60  func fromCommonToAnyOptions[T any](source uiOptions, target *T) {
    61  	var buf bytes.Buffer
    62  	enc := gob.NewEncoder(&buf)
    63  	dec := gob.NewDecoder(&buf)
    64  	err := enc.Encode(source)
    65  	if err != nil {
    66  		panic(err)
    67  	}
    68  
    69  	err = dec.Decode(target)
    70  	if err != nil {
    71  		panic(err)
    72  	}
    73  }
    74  
    75  // UIOption can be applied to UI serving middleware, such as Context.APIHandler or
    76  // Context.APIHandlerSwaggerUI to alter the defaut behavior.
    77  type UIOption func(*uiOptions)
    78  
    79  func uiOptionsWithDefaults(opts []UIOption) uiOptions {
    80  	var o uiOptions
    81  	for _, apply := range opts {
    82  		apply(&o)
    83  	}
    84  
    85  	return o
    86  }
    87  
    88  // WithUIBasePath sets the base path from where to serve the UI assets.
    89  //
    90  // By default, Context middleware sets this value to the API base path.
    91  func WithUIBasePath(base string) UIOption {
    92  	return func(o *uiOptions) {
    93  		if !strings.HasPrefix(base, "/") {
    94  			base = "/" + base
    95  		}
    96  		o.BasePath = base
    97  	}
    98  }
    99  
   100  // WithUIPath sets the path from where to serve the UI assets (i.e. /{basepath}/{path}.
   101  func WithUIPath(pth string) UIOption {
   102  	return func(o *uiOptions) {
   103  		o.Path = pth
   104  	}
   105  }
   106  
   107  // WithUISpecURL sets the path from where to serve swagger spec document.
   108  //
   109  // This may be specified as a full URL or a path.
   110  //
   111  // By default, this is "/swagger.json"
   112  func WithUISpecURL(specURL string) UIOption {
   113  	return func(o *uiOptions) {
   114  		o.SpecURL = specURL
   115  	}
   116  }
   117  
   118  // WithUITitle sets the title of the UI.
   119  //
   120  // By default, Context middleware sets this value to the title found in the API spec.
   121  func WithUITitle(title string) UIOption {
   122  	return func(o *uiOptions) {
   123  		o.Title = title
   124  	}
   125  }
   126  
   127  // WithTemplate allows to set a custom template for the UI.
   128  //
   129  // UI middleware will panic if the template does not parse or execute properly.
   130  func WithTemplate(tpl string) UIOption {
   131  	return func(o *uiOptions) {
   132  		o.Template = tpl
   133  	}
   134  }
   135  
   136  // EnsureDefaults in case some options are missing
   137  func (r *uiOptions) EnsureDefaults() {
   138  	if r.BasePath == "" {
   139  		r.BasePath = "/"
   140  	}
   141  	if r.Path == "" {
   142  		r.Path = defaultDocsPath
   143  	}
   144  	if r.SpecURL == "" {
   145  		r.SpecURL = defaultDocsURL
   146  	}
   147  	if r.Title == "" {
   148  		r.Title = defaultDocsTitle
   149  	}
   150  }
   151  
   152  // serveUI creates a middleware that serves a templated asset as text/html.
   153  func serveUI(pth string, assets []byte, next http.Handler) http.Handler {
   154  	return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
   155  		if path.Clean(r.URL.Path) == pth {
   156  			rw.Header().Set(contentTypeHeader, "text/html; charset=utf-8")
   157  			rw.WriteHeader(http.StatusOK)
   158  			_, _ = rw.Write(assets)
   159  
   160  			return
   161  		}
   162  
   163  		if next != nil {
   164  			next.ServeHTTP(rw, r)
   165  
   166  			return
   167  		}
   168  
   169  		rw.Header().Set(contentTypeHeader, "text/plain")
   170  		rw.WriteHeader(http.StatusNotFound)
   171  		_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth)))
   172  	})
   173  }
   174  

View as plain text