-
Notifications
You must be signed in to change notification settings - Fork 148
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds swagger ui as documentation option
Signed-off-by: Ivan Porto Carrero <ivan@flanders.co.nz>
- Loading branch information
Showing
3 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
package middleware | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"html/template" | ||
"net/http" | ||
"path" | ||
) | ||
|
||
// SwaggerUIOpts configures the Swaggerui middlewares | ||
type SwaggerUIOpts struct { | ||
// BasePath for the UI path, defaults to: / | ||
BasePath string | ||
// Path combines with BasePath for the full UI path, defaults to: docs | ||
Path string | ||
// SpecURL the url to find the spec for | ||
SpecURL string | ||
|
||
// The three components needed to embed swagger-ui | ||
SwaggerURL string | ||
SwaggerPresetURL string | ||
SwaggerStylesURL string | ||
|
||
Favicon32 string | ||
Favicon16 string | ||
|
||
// Title for the documentation site, default to: API documentation | ||
Title string | ||
} | ||
|
||
// EnsureDefaults in case some options are missing | ||
func (r *SwaggerUIOpts) EnsureDefaults() { | ||
if r.BasePath == "" { | ||
r.BasePath = "/" | ||
} | ||
if r.Path == "" { | ||
r.Path = "docs" | ||
} | ||
if r.SpecURL == "" { | ||
r.SpecURL = "/swagger.json" | ||
} | ||
if r.SwaggerURL == "" { | ||
r.SwaggerURL = swaggerLatest | ||
} | ||
if r.SwaggerPresetURL == "" { | ||
r.SwaggerPresetURL = swaggerPresetLatest | ||
} | ||
if r.SwaggerStylesURL == "" { | ||
r.SwaggerStylesURL = swaggerStylesLatest | ||
} | ||
if r.Favicon16 == "" { | ||
r.Favicon16 = swaggerFavicon16Latest | ||
} | ||
if r.Favicon32 == "" { | ||
r.Favicon32 = swaggerFavicon32Latest | ||
} | ||
if r.Title == "" { | ||
r.Title = "API documentation" | ||
} | ||
} | ||
|
||
// SwaggerUI creates a middleware to serve a documentation site for a swagger spec. | ||
// This allows for altering the spec before starting the http listener. | ||
func SwaggerUI(opts SwaggerUIOpts, next http.Handler) http.Handler { | ||
opts.EnsureDefaults() | ||
|
||
pth := path.Join(opts.BasePath, opts.Path) | ||
tmpl := template.Must(template.New("swaggerui").Parse(swaggeruiTemplate)) | ||
|
||
buf := bytes.NewBuffer(nil) | ||
_ = tmpl.Execute(buf, &opts) | ||
b := buf.Bytes() | ||
|
||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { | ||
if r.URL.Path == pth { | ||
rw.Header().Set("Content-Type", "text/html; charset=utf-8") | ||
rw.WriteHeader(http.StatusOK) | ||
|
||
_, _ = rw.Write(b) | ||
return | ||
} | ||
|
||
if next == nil { | ||
rw.Header().Set("Content-Type", "text/plain") | ||
rw.WriteHeader(http.StatusNotFound) | ||
_, _ = rw.Write([]byte(fmt.Sprintf("%q not found", pth))) | ||
return | ||
} | ||
next.ServeHTTP(rw, r) | ||
}) | ||
} | ||
|
||
const ( | ||
swaggerLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-bundle.js" | ||
swaggerPresetLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui-standalone-preset.js" | ||
swaggerStylesLatest = "https://unpkg.com/swagger-ui-dist/swagger-ui.css" | ||
swaggerFavicon32Latest = "https://unpkg.com/swagger-ui-dist/favicon-32x32.png" | ||
swaggerFavicon16Latest = "https://unpkg.com/swagger-ui-dist/favicon-16x16.png" | ||
swaggeruiTemplate = ` | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<title>{{ .Title }}</title> | ||
<link rel="stylesheet" type="text/css" href="{{ .SwaggerStylesURL }}" > | ||
<link rel="icon" type="image/png" href="{{ .Favicon32 }}" sizes="32x32" /> | ||
<link rel="icon" type="image/png" href="{{ .Favicon16 }}" sizes="16x16" /> | ||
<style> | ||
html | ||
{ | ||
box-sizing: border-box; | ||
overflow: -moz-scrollbars-vertical; | ||
overflow-y: scroll; | ||
} | ||
*, | ||
*:before, | ||
*:after | ||
{ | ||
box-sizing: inherit; | ||
} | ||
body | ||
{ | ||
margin:0; | ||
background: #fafafa; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="swagger-ui"></div> | ||
<script src="{{ .SwaggerURL }}"> </script> | ||
<script src="{{ .SwaggerPresetURL }}"> </script> | ||
<script> | ||
window.onload = function() { | ||
// Begin Swagger UI call region | ||
const ui = SwaggerUIBundle({ | ||
url: '{{ .SpecURL }}', | ||
dom_id: '#swagger-ui', | ||
deepLinking: true, | ||
presets: [ | ||
SwaggerUIBundle.presets.apis, | ||
SwaggerUIStandalonePreset | ||
], | ||
plugins: [ | ||
SwaggerUIBundle.plugins.DownloadUrl | ||
], | ||
layout: "StandaloneLayout" | ||
}) | ||
// End Swagger UI call region | ||
window.ui = ui | ||
} | ||
</script> | ||
</body> | ||
</html> | ||
` | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package middleware | ||
|
||
import ( | ||
"net/http" | ||
"net/http/httptest" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestSwaggerUIMiddleware(t *testing.T) { | ||
redoc := SwaggerUI(SwaggerUIOpts{}, nil) | ||
|
||
req, _ := http.NewRequest("GET", "/docs", nil) | ||
recorder := httptest.NewRecorder() | ||
redoc.ServeHTTP(recorder, req) | ||
assert.Equal(t, 200, recorder.Code) | ||
assert.Equal(t, "text/html; charset=utf-8", recorder.Header().Get("Content-Type")) | ||
assert.Contains(t, recorder.Body.String(), "<title>API documentation</title>") | ||
assert.Contains(t, recorder.Body.String(), "url: '\\/swagger.json',") | ||
assert.Contains(t, recorder.Body.String(), swaggerLatest) | ||
assert.Contains(t, recorder.Body.String(), swaggerPresetLatest) | ||
assert.Contains(t, recorder.Body.String(), swaggerStylesLatest) | ||
assert.Contains(t, recorder.Body.String(), swaggerFavicon16Latest) | ||
assert.Contains(t, recorder.Body.String(), swaggerFavicon32Latest) | ||
} |