feat(http): host swagger docs at /docs and /api/v2/swagger.json

pull/11366/head
Chris Goller 2019-01-22 11:16:27 -06:00
parent e6a6e50b82
commit a11773838f
6 changed files with 111 additions and 2 deletions

View File

@ -3,10 +3,10 @@ TARGETS = ../ui/src/api/api.ts
# List any source files used to generate the targets here
SOURCES = cur_swagger.yml
# List any directories that have their own Makefile here
SUBDIRS =
SUBDIRS =
# Default target
all: $(SUBDIRS) $(TARGETS)
all: $(SUBDIRS) $(TARGETS) swagger_gen.go
# Recurse into subdirs for same make goal
$(SUBDIRS):
@ -15,7 +15,11 @@ $(SUBDIRS):
# Clean all targets recursively
clean: $(SUBDIRS)
rm -f $(TARGETS)
rm -f swagger_gen.go
swagger_gen.go: swagger.go redoc.go swagger.yml
go generate -x
echo '//lint:file-ignore ST1005 Ignore error strings should not be capitalized' >> swagger_gen.go
GO_RUN := env GO111MODULE=on go run

View File

@ -32,6 +32,7 @@ type APIHandler struct {
WriteHandler *WriteHandler
SetupHandler *SetupHandler
SessionHandler *SessionHandler
SwaggerHandler http.HandlerFunc
}
// APIBackend is all services and associated parameters required to construct
@ -153,6 +154,8 @@ func NewAPIHandler(b *APIBackend) *APIHandler {
h.ChronografHandler = NewChronografHandler(b.ChronografService)
h.SwaggerHandler = SwaggerHandler()
return h
}
@ -182,6 +185,7 @@ var apiLinks = map[string]interface{}{
"signout": "/api/v2/signout",
"sources": "/api/v2/sources",
"scrapers": "/api/v2/scrapers",
"swagger": "/api/v2/swagger.json",
"system": map[string]string{
"metrics": "/metrics",
"debug": "/debug/pprof",
@ -304,5 +308,10 @@ func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
if r.URL.Path == "/api/v2/swagger.json" {
h.SwaggerHandler.ServeHTTP(w, r)
return
}
notFoundHandler(w, r)
}

15
http/no_assets.go Normal file
View File

@ -0,0 +1,15 @@
// +build !assets
package http
import (
"errors"
)
// The functions defined in this file are placeholders when the binary is compiled
// without assets.
// Asset returns an error stating no assets were included in the binary.
func Asset(string) ([]byte, error) {
return nil, errors.New("no assets included in binary")
}

View File

@ -10,6 +10,7 @@ import (
// PlatformHandler is a collection of all the service handlers.
type PlatformHandler struct {
AssetHandler *AssetHandler
DocsHandler http.HandlerFunc
APIHandler http.Handler
}
@ -33,12 +34,14 @@ func NewPlatformHandler(b *APIBackend) *PlatformHandler {
h.RegisterNoAuthRoute("POST", "/api/v2/signout")
h.RegisterNoAuthRoute("POST", "/api/v2/setup")
h.RegisterNoAuthRoute("GET", "/api/v2/setup")
h.RegisterNoAuthRoute("GET", "/api/v2/swagger.json")
assetHandler := NewAssetHandler()
assetHandler.DeveloperMode = b.DeveloperMode
return &PlatformHandler{
AssetHandler: assetHandler,
DocsHandler: Redoc("/api/v2/swagger.json"),
APIHandler: h,
}
}
@ -50,6 +53,11 @@ func (h *PlatformHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
if strings.HasPrefix(r.URL.Path, "/docs") {
h.DocsHandler.ServeHTTP(w, r)
return
}
// Serve the chronograf assets for any basepath that does not start with addressable parts
// of the platform API.
if !strings.HasPrefix(r.URL.Path, "/v1") &&

39
http/redoc.go Normal file
View File

@ -0,0 +1,39 @@
package http
import (
"fmt"
"net/http"
)
const index = `<!DOCTYPE html>
<html>
<head>
<title>Chronograf API</title>
<!-- needed for adaptive design -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!--
ReDoc doesn't change outer page styles
-->
<style>
body {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<redoc spec-url='%s' suppressWarnings=true></redoc>
<script src="https://cdn.jsdelivr.net/npm/redoc/bundles/redoc.standalone.js"> </script>
</body>
</html>
`
// Redoc servers the swagger JSON using the redoc package.
func Redoc(swagger string) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte(fmt.Sprintf(index, swagger)))
})
}

34
http/swagger.go Normal file
View File

@ -0,0 +1,34 @@
package http
//go:generate env GO111MODULE=on go run github.com/kevinburke/go-bindata/go-bindata -o swagger_gen.go -tags assets -ignore go -nocompress -pkg http .
import (
"context"
"net/http"
"github.com/ghodss/yaml"
"github.com/influxdata/influxdb"
)
// SwaggerHandler servers the swagger.json file from bindata
func SwaggerHandler() http.HandlerFunc {
swagger, err := Asset("swagger.yml")
var json []byte
if err == nil {
json, err = yaml.YAMLToJSON(swagger)
}
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err != nil {
EncodeError(context.Background(), &influxdb.Error{
Err: err,
Msg: "this developer binary not built with assets",
Code: influxdb.EInternal,
}, w)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, _ = w.Write(json)
})
}