github.com/weaviate/weaviate@v1.24.6/adapters/handlers/rest/swagger_middleware/swagger_middleware.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package swagger_middleware
    13  
    14  import (
    15  	"fmt"
    16  	"html/template"
    17  	"net/http"
    18  	"strings"
    19  )
    20  
    21  const swaggerUIVersion = "3.19.4"
    22  
    23  type templateData struct {
    24  	Prefix   string
    25  	APIKey   string
    26  	APIToken string
    27  }
    28  
    29  func AddMiddleware(swaggerJSON []byte, next http.Handler) http.Handler {
    30  	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    31  		if strings.HasPrefix(r.URL.Path, "/v1/swagger.json") && r.Method == http.MethodGet {
    32  			w.Header().Set("Content-Type", "application/json")
    33  			w.Write(swaggerJSON)
    34  		} else if strings.HasPrefix(r.URL.Path, "/v1/swagger") && r.Method == http.MethodGet {
    35  			renderSwagger(w, r)
    36  		} else {
    37  			next.ServeHTTP(w, r)
    38  		}
    39  	})
    40  }
    41  
    42  // renderswagger renders the swagger GUI
    43  func renderSwagger(w http.ResponseWriter, r *http.Request) {
    44  	w.Header().Set("WWW-Authenticate", `Basic realm="Provide your key and token (as username as password respectively)"`)
    45  
    46  	user, password, authOk := r.BasicAuth()
    47  	if !authOk {
    48  		http.Error(w, "Not authorized", 401)
    49  		return
    50  	}
    51  
    52  	t := template.New("Swagger")
    53  	t, err := t.Parse(swaggerTemplate)
    54  	if err != nil {
    55  		http.Error(w, err.Error(), http.StatusInternalServerError)
    56  		return
    57  	}
    58  
    59  	// Create result string
    60  	d := templateData{
    61  		Prefix:   fmt.Sprintf("https://cdn.jsdelivr.net/npm/swagger-ui-dist@%s", swaggerUIVersion),
    62  		APIKey:   user,
    63  		APIToken: password,
    64  	}
    65  
    66  	err = t.ExecuteTemplate(w, "index", d)
    67  	if err != nil {
    68  		http.Error(w, err.Error(), http.StatusInternalServerError)
    69  	}
    70  }
    71  
    72  // tmpl is the page template to render GraphiQL
    73  const swaggerTemplate = `
    74  {{ define "index" }}
    75  <!-- HTML for static distribution bundle build -->
    76  <!DOCTYPE html>
    77  <html lang="en">
    78    <head>
    79      <meta charset="UTF-8">
    80      <title>Weaviate API</title>
    81      <link rel="stylesheet" type="text/css" href="{{ .Prefix }}/swagger-ui.css" >
    82      <link rel="icon" type="image/png" href="{{ .Prefix }}/favicon-32x32.png" sizes="32x32" />
    83      <link rel="icon" type="image/png" href="{{ .Prefix }}/favicon-16x16.png" sizes="16x16" />
    84      <style>
    85        html
    86        {
    87          box-sizing: border-box;
    88          overflow: -moz-scrollbars-vertical;
    89          overflow-y: scroll;
    90        }
    91  
    92        *,
    93        *:before,
    94        *:after
    95        {
    96          box-sizing: inherit;
    97        }
    98  
    99        body
   100        {
   101          margin:0;
   102          background: #fafafa;
   103        }
   104      </style>
   105    </head>
   106  
   107    <body>
   108      <div id="swagger-ui"></div>
   109  
   110      <script src="{{ .Prefix }}/swagger-ui-bundle.js"> </script>
   111      <script src="{{ .Prefix }}/swagger-ui-standalone-preset.js"> </script>
   112      <script>
   113      window.onload = function() {
   114  
   115        // Build a system
   116        const ui = SwaggerUIBundle({
   117          url: "/v1/swagger.json",
   118          dom_id: '#swagger-ui',
   119          deepLinking: true,
   120          presets: [
   121            SwaggerUIBundle.presets.apis,
   122            SwaggerUIStandalonePreset
   123          ],
   124          requestInterceptor: function(request) {
   125            request.headers["X-API-KEY"] = "{{ .APIKey }}"
   126            request.headers["X-API-TOKEN"] = "{{ .APIToken }}"
   127  
   128            var requestUrl = null
   129            try {
   130              requestUrl = new URL(request.url)
   131            } catch (err) {
   132              console.log("Could not parse url in request", request, "; not checking if we need to change the protocol.")
   133            }
   134  
   135            if (requestUrl != null && requestUrl.protocol != location.protocol) {
   136              requestUrl.protocol = location.protocol
   137              request.url = requestUrl.toString()
   138            }
   139  
   140            return request
   141          },
   142          plugins: [
   143            SwaggerUIBundle.plugins.DownloadUrl
   144          ],
   145          layout: "StandaloneLayout"
   146        })
   147  
   148        window.ui = ui
   149      }
   150    </script>
   151    </body>
   152  </html>
   153  {{ end }}
   154  `