From d7e2f9ed225e1d0c29f1bfd2957240f3e2aadd90 Mon Sep 17 00:00:00 2001 From: danysousa Date: Wed, 30 Nov 2022 15:05:35 +0100 Subject: [PATCH] [OpenAPI] Add a way to add middleware to openAPI handlers & customisation --- openapi/config.go | 22 ++++++++++++++++++++-- openapi/handler.go | 23 +++++++++-------------- openapi/rapidoc.go | 47 ++++++++++++++++++++++++++++++++++++++-------- server/openapi.go | 9 +++++---- 4 files changed, 73 insertions(+), 28 deletions(-) diff --git a/openapi/config.go b/openapi/config.go index 8395d37..63c55cb 100644 --- a/openapi/config.go +++ b/openapi/config.go @@ -7,6 +7,8 @@ import ( const ( // DefaultDocURI is the URI used to host documentation UI DefaultDocURI = "/" + // DocPageTitle is the URI used to host documentation UI + DocPageTitle = "Doc | API" // DefaultSpecOpenAPIURI is the URI used to host the openapi file generated by this package DefaultSpecOpenAPIURI = "/openapi.json" ) @@ -27,8 +29,10 @@ type config struct { SpecOpenAPIURI string // IgnoredPaths are the paths that shouldn't be included in the documentation. IgnoredPaths []string - // Auth is your auth system to protect your documentation. - Auth Authorization + // DocPageTitle is used as doc title + DocPageTitle string + // FaviconURL is used for web doc UI + FaviconURL string } // GetDocURI return config.DocURI if a values was set otherwise DefaultDocURI is returned @@ -63,3 +67,17 @@ func (c config) ignoredPaths() []string { return append(ignoredPaths, c.IgnoredPaths...) } + +// GetDocPageTitle return config.DocPageTitle if a values was set otherwise DocPageTitle is returned +func (c config) GetDocPageTitle() string { + if c.DocPageTitle != "" { + return c.DocPageTitle + } + + return DocPageTitle +} + +// GetFaviconURL return config.FaviconURL +func (c config) GetFaviconURL() string { + return c.FaviconURL +} diff --git a/openapi/handler.go b/openapi/handler.go index b0aa6c5..bc8ef6b 100644 --- a/openapi/handler.go +++ b/openapi/handler.go @@ -6,23 +6,27 @@ import ( "github.com/gorilla/mux" "github.com/swaggest/openapi-go/openapi3" + + "github.com/mwm-io/gapi/handler" ) // SpecOpenAPIHandler is a server.SpecOpenAPIHandler that will return a json openapi definition of the given reflector. type SpecOpenAPIHandler struct { + handler.WithMiddlewares _reflector *openapi3.Reflector reflectorOnce sync.Once computeDocError error router *mux.Router - // auth Authorization } // NewSpecOpenAPIHandler builds a new SpecOpenAPIHandler, serving the api definition from the openapi3.Reflector, // and checking auth access with the given Authorization. -func NewSpecOpenAPIHandler(router *mux.Router) *SpecOpenAPIHandler { +func NewSpecOpenAPIHandler(router *mux.Router, middlewares ...handler.Middleware) *SpecOpenAPIHandler { return &SpecOpenAPIHandler{ router: router, - // auth: auth, TODO : change it by a middleware + WithMiddlewares: handler.WithMiddlewares{ + MiddlewareList: middlewares, + }, } } @@ -32,6 +36,7 @@ func NewSpecOpenAPIHandler(router *mux.Router) *SpecOpenAPIHandler { func (h *SpecOpenAPIHandler) getReflector() (*openapi3.Reflector, error) { h.reflectorOnce.Do(func() { h._reflector = new(openapi3.Reflector) + h._reflector.SpecEns().Info.WithTitle(Config.GetDocPageTitle()) h.computeDocError = PopulateReflector(h._reflector, h.router, Config.ignoredPaths()) }) @@ -39,17 +44,7 @@ func (h *SpecOpenAPIHandler) getReflector() (*openapi3.Reflector, error) { } // Serve implements the handler.Handler interface -func (h *SpecOpenAPIHandler) Serve(w http.ResponseWriter, r *http.Request) (interface{}, error) { - // if h.auth != nil { - // authorized, err := h.auth.Authorize(w, r) - // if err != nil { - // return nil, err - // } - // if !authorized { - // return h.auth.Login(w, r) - // } - // } - +func (h *SpecOpenAPIHandler) Serve(_ http.ResponseWriter, _ *http.Request) (interface{}, error) { reflector, err := h.getReflector() if err != nil { return nil, err diff --git a/openapi/rapidoc.go b/openapi/rapidoc.go index 57f3b4a..1fe61c9 100644 --- a/openapi/rapidoc.go +++ b/openapi/rapidoc.go @@ -1,48 +1,79 @@ package openapi import ( + "fmt" "net/http" "strings" + + "github.com/mwm-io/gapi/handler" ) // RapiDocHandler is a server.SpecOpenAPIHandler that will serve a html page with rapidoc loading the given openAPIJsonURL type RapiDocHandler struct { + handler.WithMiddlewares openAPIJsonURL string } // NewRapiDocHandler build a new RapiDocHandler. -func NewRapiDocHandler() RapiDocHandler { - return RapiDocHandler{ +func NewRapiDocHandler(middlewares ...handler.Middleware) handler.Handler { + return &RapiDocHandler{ openAPIJsonURL: Config.GetSpecOpenAPIURI(), + WithMiddlewares: handler.WithMiddlewares{ + MiddlewareList: middlewares, + }, } } -// Serve implements the server.SpecOpenAPIHandler interface -func (h RapiDocHandler) Serve(w http.ResponseWriter, r *http.Request) (interface{}, error) { +// Serve implements the handler.Handler interface +func (h RapiDocHandler) Serve(_ http.ResponseWriter, _ *http.Request) (interface{}, error) { // TODO add customisation options : like icon, theme etc... - // TODO add auth middleware as option + + var favicon string + if faviconURL := Config.GetFaviconURL(); faviconURL != "" { + favicon = fmt.Sprintf(``, faviconURL) + } + return strings.NewReader(` + ` + Config.GetDocPageTitle() + ` + ` + favicon + ` `), nil } // RapiDocReceiverHandler is a server.SpecOpenAPIHandler that will serve the rapidoc oauth receiver -func RapiDocReceiverHandler(w http.ResponseWriter, r *http.Request) (interface{}, error) { +type RapiDocReceiverHandler struct { + handler.WithMiddlewares +} + +// NewRapiDocReceiverHandler build a new RapiDocReceiverHandler. +func NewRapiDocReceiverHandler(middlewares ...handler.Middleware) handler.Handler { + return &RapiDocReceiverHandler{ + WithMiddlewares: handler.WithMiddlewares{ + MiddlewareList: middlewares, + }, + } +} + +// Serve implements the handler.Handler interface +func (h RapiDocReceiverHandler) Serve(_ http.ResponseWriter, _ *http.Request) (interface{}, error) { return strings.NewReader(` diff --git a/server/openapi.go b/server/openapi.go index 5e8e875..e8f96ce 100644 --- a/server/openapi.go +++ b/server/openapi.go @@ -4,6 +4,7 @@ import ( "net/http" "github.com/gorilla/mux" + "github.com/mwm-io/gapi/handler" "github.com/mwm-io/gapi/openapi" ) @@ -11,11 +12,11 @@ import ( // AddDocHandlers will add the necessary handlers to serve a rapidoc endpoint: // 2 endpoints to serve rapidoc.html and oauth-receiver.html from rapidoc // and one endpoint to serve the json openapi definition of your API. -func AddDocHandlers(r *mux.Router) error { +func AddDocHandlers(r *mux.Router, middlewares ...handler.Middleware) error { - AddHandler(r, http.MethodGet, openapi.Config.GetDocURI(), openapi.NewRapiDocHandler()) - AddHandler(r, http.MethodGet, openapi.Config.GetAuthReceiverURI(), handler.Func(openapi.RapiDocReceiverHandler)) - AddHandler(r, http.MethodGet, openapi.Config.GetSpecOpenAPIURI(), openapi.NewSpecOpenAPIHandler(r)) + AddHandler(r, http.MethodGet, openapi.Config.GetDocURI(), openapi.NewRapiDocHandler(middlewares...)) + AddHandler(r, http.MethodGet, openapi.Config.GetAuthReceiverURI(), openapi.NewRapiDocReceiverHandler(middlewares...)) + AddHandler(r, http.MethodGet, openapi.Config.GetSpecOpenAPIURI(), openapi.NewSpecOpenAPIHandler(r, middlewares...)) return nil }