feat(http): host swagger docs at /docs and /api/v2/swagger.json
parent
e6a6e50b82
commit
a11773838f
|
@ -6,7 +6,7 @@ SOURCES = cur_swagger.yml
|
||||||
SUBDIRS =
|
SUBDIRS =
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
all: $(SUBDIRS) $(TARGETS)
|
all: $(SUBDIRS) $(TARGETS) swagger_gen.go
|
||||||
|
|
||||||
# Recurse into subdirs for same make goal
|
# Recurse into subdirs for same make goal
|
||||||
$(SUBDIRS):
|
$(SUBDIRS):
|
||||||
|
@ -15,7 +15,11 @@ $(SUBDIRS):
|
||||||
# Clean all targets recursively
|
# Clean all targets recursively
|
||||||
clean: $(SUBDIRS)
|
clean: $(SUBDIRS)
|
||||||
rm -f $(TARGETS)
|
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
|
GO_RUN := env GO111MODULE=on go run
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ type APIHandler struct {
|
||||||
WriteHandler *WriteHandler
|
WriteHandler *WriteHandler
|
||||||
SetupHandler *SetupHandler
|
SetupHandler *SetupHandler
|
||||||
SessionHandler *SessionHandler
|
SessionHandler *SessionHandler
|
||||||
|
SwaggerHandler http.HandlerFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
// APIBackend is all services and associated parameters required to construct
|
// 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.ChronografHandler = NewChronografHandler(b.ChronografService)
|
||||||
|
|
||||||
|
h.SwaggerHandler = SwaggerHandler()
|
||||||
|
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,6 +185,7 @@ var apiLinks = map[string]interface{}{
|
||||||
"signout": "/api/v2/signout",
|
"signout": "/api/v2/signout",
|
||||||
"sources": "/api/v2/sources",
|
"sources": "/api/v2/sources",
|
||||||
"scrapers": "/api/v2/scrapers",
|
"scrapers": "/api/v2/scrapers",
|
||||||
|
"swagger": "/api/v2/swagger.json",
|
||||||
"system": map[string]string{
|
"system": map[string]string{
|
||||||
"metrics": "/metrics",
|
"metrics": "/metrics",
|
||||||
"debug": "/debug/pprof",
|
"debug": "/debug/pprof",
|
||||||
|
@ -304,5 +308,10 @@ func (h *APIHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if r.URL.Path == "/api/v2/swagger.json" {
|
||||||
|
h.SwaggerHandler.ServeHTTP(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
notFoundHandler(w, r)
|
notFoundHandler(w, r)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import (
|
||||||
// PlatformHandler is a collection of all the service handlers.
|
// PlatformHandler is a collection of all the service handlers.
|
||||||
type PlatformHandler struct {
|
type PlatformHandler struct {
|
||||||
AssetHandler *AssetHandler
|
AssetHandler *AssetHandler
|
||||||
|
DocsHandler http.HandlerFunc
|
||||||
APIHandler http.Handler
|
APIHandler http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,12 +34,14 @@ func NewPlatformHandler(b *APIBackend) *PlatformHandler {
|
||||||
h.RegisterNoAuthRoute("POST", "/api/v2/signout")
|
h.RegisterNoAuthRoute("POST", "/api/v2/signout")
|
||||||
h.RegisterNoAuthRoute("POST", "/api/v2/setup")
|
h.RegisterNoAuthRoute("POST", "/api/v2/setup")
|
||||||
h.RegisterNoAuthRoute("GET", "/api/v2/setup")
|
h.RegisterNoAuthRoute("GET", "/api/v2/setup")
|
||||||
|
h.RegisterNoAuthRoute("GET", "/api/v2/swagger.json")
|
||||||
|
|
||||||
assetHandler := NewAssetHandler()
|
assetHandler := NewAssetHandler()
|
||||||
assetHandler.DeveloperMode = b.DeveloperMode
|
assetHandler.DeveloperMode = b.DeveloperMode
|
||||||
|
|
||||||
return &PlatformHandler{
|
return &PlatformHandler{
|
||||||
AssetHandler: assetHandler,
|
AssetHandler: assetHandler,
|
||||||
|
DocsHandler: Redoc("/api/v2/swagger.json"),
|
||||||
APIHandler: h,
|
APIHandler: h,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +53,11 @@ func (h *PlatformHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
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
|
// Serve the chronograf assets for any basepath that does not start with addressable parts
|
||||||
// of the platform API.
|
// of the platform API.
|
||||||
if !strings.HasPrefix(r.URL.Path, "/v1") &&
|
if !strings.HasPrefix(r.URL.Path, "/v1") &&
|
||||||
|
|
|
@ -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)))
|
||||||
|
})
|
||||||
|
}
|
|
@ -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)
|
||||||
|
})
|
||||||
|
}
|
Loading…
Reference in New Issue