mirror of
https://github.com/davidebianchi/gswagger.git
synced 2025-12-23 23:38:43 -05:00
Merge pull request #11 from davidebianchi/custom-docs-path
feat: add custom documentation path
This commit is contained in:
@@ -34,7 +34,7 @@ func TestIntegration(t *testing.T) {
|
||||
|
||||
t.Run("and generate swagger", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, JSONDocumentationPath, nil)
|
||||
r := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
|
||||
58
main.go
58
main.go
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/ghodss/yaml"
|
||||
@@ -19,24 +20,30 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
// JSONDocumentationPath is the path of the swagger documentation in json format.
|
||||
JSONDocumentationPath = "/documentation/json"
|
||||
// YAMLDocumentationPath is the path of the swagger documentation in yaml format.
|
||||
YAMLDocumentationPath = "/documentation/yaml"
|
||||
defaultOpenapiVersion = "3.0.0"
|
||||
// DefaultJSONDocumentationPath is the path of the swagger documentation in json format.
|
||||
DefaultJSONDocumentationPath = "/documentation/json"
|
||||
// DefaultYAMLDocumentationPath is the path of the swagger documentation in yaml format.
|
||||
DefaultYAMLDocumentationPath = "/documentation/yaml"
|
||||
defaultOpenapiVersion = "3.0.0"
|
||||
)
|
||||
|
||||
// Router handle the gorilla mux router and the swagger schema
|
||||
type Router struct {
|
||||
router *mux.Router
|
||||
swaggerSchema *openapi3.Swagger
|
||||
context context.Context
|
||||
router *mux.Router
|
||||
swaggerSchema *openapi3.Swagger
|
||||
context context.Context
|
||||
jsonDocumentationPath string
|
||||
yamlDocumentationPath string
|
||||
}
|
||||
|
||||
// Options to be passed to create the new router and swagger
|
||||
type Options struct {
|
||||
Context context.Context
|
||||
Openapi *openapi3.Swagger
|
||||
// JSONDocumentationPath is the path exposed by json endpoint. Default to /documentation/json.
|
||||
JSONDocumentationPath string
|
||||
// YAMLDocumentationPath is the path exposed by yaml endpoint. Default to /documentation/yaml.
|
||||
YAMLDocumentationPath string
|
||||
}
|
||||
|
||||
// NewRouter generate new router with swagger. Default to OpenAPI 3.0.0
|
||||
@@ -51,10 +58,28 @@ func NewRouter(router *mux.Router, options Options) (*Router, error) {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
yamlDocumentationPath := DefaultYAMLDocumentationPath
|
||||
if options.YAMLDocumentationPath != "" {
|
||||
if err := isValidDocumentationPath(options.YAMLDocumentationPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
yamlDocumentationPath = options.YAMLDocumentationPath
|
||||
}
|
||||
|
||||
jsonDocumentationPath := DefaultJSONDocumentationPath
|
||||
if options.JSONDocumentationPath != "" {
|
||||
if err := isValidDocumentationPath(options.JSONDocumentationPath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonDocumentationPath = options.JSONDocumentationPath
|
||||
}
|
||||
|
||||
return &Router{
|
||||
router: router,
|
||||
swaggerSchema: swagger,
|
||||
context: ctx,
|
||||
router: router,
|
||||
swaggerSchema: swagger,
|
||||
context: ctx,
|
||||
yamlDocumentationPath: yamlDocumentationPath,
|
||||
jsonDocumentationPath: jsonDocumentationPath,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -93,7 +118,7 @@ func (r Router) GenerateAndExposeSwagger() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w json marshal: %s", ErrGenerateSwagger, err)
|
||||
}
|
||||
r.router.HandleFunc(JSONDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
r.router.HandleFunc(r.jsonDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(jsonSwagger)
|
||||
@@ -103,7 +128,7 @@ func (r Router) GenerateAndExposeSwagger() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w yaml marshal: %s", ErrGenerateSwagger, err)
|
||||
}
|
||||
r.router.HandleFunc(YAMLDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
r.router.HandleFunc(r.yamlDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(yamlSwagger)
|
||||
@@ -111,3 +136,10 @@ func (r Router) GenerateAndExposeSwagger() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isValidDocumentationPath(path string) error {
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
return fmt.Errorf("invalid path %s. Path should start with '/'", path)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
122
main_test.go
122
main_test.go
@@ -40,9 +40,11 @@ func TestNewRouter(t *testing.T) {
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &Router{
|
||||
context: context.Background(),
|
||||
router: mRouter,
|
||||
swaggerSchema: openapi,
|
||||
context: context.Background(),
|
||||
router: mRouter,
|
||||
swaggerSchema: openapi,
|
||||
jsonDocumentationPath: DefaultJSONDocumentationPath,
|
||||
yamlDocumentationPath: DefaultYAMLDocumentationPath,
|
||||
}, r)
|
||||
})
|
||||
|
||||
@@ -56,11 +58,61 @@ func TestNewRouter(t *testing.T) {
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &Router{
|
||||
context: ctx,
|
||||
router: mRouter,
|
||||
swaggerSchema: openapi,
|
||||
context: ctx,
|
||||
router: mRouter,
|
||||
swaggerSchema: openapi,
|
||||
jsonDocumentationPath: DefaultJSONDocumentationPath,
|
||||
yamlDocumentationPath: DefaultYAMLDocumentationPath,
|
||||
}, r)
|
||||
})
|
||||
|
||||
t.Run("ok - with custom docs paths", func(t *testing.T) {
|
||||
type key struct{}
|
||||
ctx := context.WithValue(context.Background(), key{}, "value")
|
||||
r, err := NewRouter(mRouter, Options{
|
||||
Openapi: openapi,
|
||||
Context: ctx,
|
||||
JSONDocumentationPath: "/json/path",
|
||||
YAMLDocumentationPath: "/yaml/path",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &Router{
|
||||
context: ctx,
|
||||
router: mRouter,
|
||||
swaggerSchema: openapi,
|
||||
jsonDocumentationPath: "/json/path",
|
||||
yamlDocumentationPath: "/yaml/path",
|
||||
}, r)
|
||||
})
|
||||
|
||||
t.Run("ko - json documentation path does not start with /", func(t *testing.T) {
|
||||
type key struct{}
|
||||
ctx := context.WithValue(context.Background(), key{}, "value")
|
||||
r, err := NewRouter(mRouter, Options{
|
||||
Openapi: openapi,
|
||||
Context: ctx,
|
||||
JSONDocumentationPath: "json/path",
|
||||
YAMLDocumentationPath: "/yaml/path",
|
||||
})
|
||||
|
||||
require.EqualError(t, err, "invalid path json/path. Path should start with '/'")
|
||||
require.Nil(t, r)
|
||||
})
|
||||
|
||||
t.Run("ko - yaml documentation path does not start with /", func(t *testing.T) {
|
||||
type key struct{}
|
||||
ctx := context.WithValue(context.Background(), key{}, "value")
|
||||
r, err := NewRouter(mRouter, Options{
|
||||
Openapi: openapi,
|
||||
Context: ctx,
|
||||
JSONDocumentationPath: "/json/path",
|
||||
YAMLDocumentationPath: "yaml/path",
|
||||
})
|
||||
|
||||
require.EqualError(t, err, "invalid path yaml/path. Path should start with '/'")
|
||||
require.Nil(t, r)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGenerateValidSwagger(t *testing.T) {
|
||||
@@ -166,7 +218,34 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, JSONDocumentationPath, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
|
||||
mRouter.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
actual, err := ioutil.ReadFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, string(actual), body)
|
||||
})
|
||||
|
||||
t.Run("correctly expose json documentation from loaded swagger file - custom path", func(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
|
||||
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
Openapi: swagger,
|
||||
JSONDocumentationPath: "/custom/path",
|
||||
})
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
||||
mRouter.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
@@ -192,7 +271,34 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, YAMLDocumentationPath, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, DefaultYAMLDocumentationPath, nil)
|
||||
mRouter.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "text/plain"))
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
expected, err := ioutil.ReadFile("testdata/users_employees.yaml")
|
||||
require.NoError(t, err)
|
||||
require.YAMLEq(t, string(expected), body, string(body))
|
||||
})
|
||||
|
||||
t.Run("correctly expose yaml documentation from loaded swagger file - custom path", func(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
|
||||
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
Openapi: swagger,
|
||||
YAMLDocumentationPath: "/custom/path",
|
||||
})
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
|
||||
mRouter.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
@@ -386,7 +386,7 @@ func TestAddRoutes(t *testing.T) {
|
||||
|
||||
t.Run("and generate swagger documentation in json", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest(http.MethodGet, JSONDocumentationPath, nil)
|
||||
req := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
|
||||
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user