13 Commits

Author SHA1 Message Date
Davide Bianchi
ffb0e6b3f7 docs: update CHANGELOG 2021-11-10 10:41:38 +01:00
Davide Bianchi
94abd8f4bf docs: update README 2021-11-10 10:39:59 +01:00
Davide Bianchi
7232d5d823 feat: add coverage report 2021-11-10 10:34:38 +01:00
Davide Bianchi
b26ddbeecf Update test-builds.yml 2021-11-10 10:30:40 +01:00
Davide Bianchi
3374e2bd80 Merge pull request #36 from davidebianchi/feat/subrouter-path-prefix 2021-11-10 10:27:22 +01:00
Davide Bianchi
33d81e9cdd docs: update CHANGELOG 2021-11-10 10:23:17 +01:00
Davide Bianchi
a7a671be5a test: add route with path equal to prefix path 2021-11-10 10:22:45 +01:00
Davide Bianchi
239a70a1a0 test: more simple test 2021-11-10 10:15:55 +01:00
Davide Bianchi
8c0aacb68c fix: remove GetSwaggerSchema fn 2021-11-10 10:13:51 +01:00
Davide Bianchi
d145c6ca5d feat: add SubRouter method 2021-11-10 10:12:26 +01:00
Davide Bianchi
a8c5be8870 feat: add SubRouter method 2021-11-10 10:02:32 +01:00
Davide Bianchi
8fda85d9d3 docs: update CHANGELOG 2021-11-09 22:36:56 +01:00
Davide Bianchi
a872dd02b7 feat: add support to subrouter, handle path prefix 2021-11-09 22:35:17 +01:00
8 changed files with 196 additions and 15 deletions

View File

@@ -26,7 +26,11 @@ jobs:
go get -v -t -d ./...
- name: Run tests
run: |
go test ./... -count=1 -race -cover
go test ./... -count=1 -race -cover -coverprofile cover.out
- name: Build
run: |
go build -v .
- name: Send the coverage output
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: cover.out

View File

@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## v0.3.0 - 10-11-2021
### Added
- handle router with path prefix
- add SubRouter method to use a new sub router
## v0.2.0 - 16-10-2021
### BREAKING CHANGES

View File

@@ -1,6 +1,7 @@
<div align="center">
[![Build Status][github-actions-svg]][github-actions]
[![Coverage Status](https://coveralls.io/repos/github/davidebianchi/gswagger/badge.svg?branch=main)](https://coveralls.io/github/davidebianchi/gswagger?branch=main)
[![Go Report Card][go-report-card]][go-report-card-link]
[![GoDoc][godoc-svg]][godoc-link]

19
main.go
View File

@@ -36,6 +36,7 @@ type Router struct {
context context.Context
jsonDocumentationPath string
yamlDocumentationPath string
pathPrefix string
}
// Options to be passed to create the new router and swagger
@@ -46,6 +47,8 @@ type Options struct {
JSONDocumentationPath string
// YAMLDocumentationPath is the path exposed by yaml endpoint. Default to /documentation/yaml.
YAMLDocumentationPath string
// Add path prefix to add to every router path.
PathPrefix string
}
// NewRouter generate new router with swagger. Default to OpenAPI 3.0.0
@@ -82,6 +85,22 @@ func NewRouter(router apirouter.Router, options Options) (*Router, error) {
context: ctx,
yamlDocumentationPath: yamlDocumentationPath,
jsonDocumentationPath: jsonDocumentationPath,
pathPrefix: options.PathPrefix,
}, nil
}
type SubRouterOptions struct {
PathPrefix string
}
func (r Router) SubRouter(router apirouter.Router, opts SubRouterOptions) (*Router, error) {
return &Router{
router: router,
swaggerSchema: r.swaggerSchema,
context: r.context,
jsonDocumentationPath: r.jsonDocumentationPath,
yamlDocumentationPath: r.yamlDocumentationPath,
pathPrefix: opts.PathPrefix,
}, nil
}

View File

@@ -17,7 +17,8 @@ import (
)
func TestNewRouter(t *testing.T) {
mRouter := apirouter.NewGorillaMuxRouter(mux.NewRouter())
muxRouter := mux.NewRouter()
mAPIRouter := apirouter.NewGorillaMuxRouter(muxRouter)
info := &openapi3.Info{
Title: "my title",
@@ -29,21 +30,21 @@ func TestNewRouter(t *testing.T) {
}
t.Run("not ok - invalid Openapi option", func(t *testing.T) {
r, err := NewRouter(mRouter, Options{})
r, err := NewRouter(mAPIRouter, Options{})
require.Nil(t, r)
require.EqualError(t, err, fmt.Sprintf("%s: swagger is required", ErrValidatingSwagger))
})
t.Run("ok - with default context", func(t *testing.T) {
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
})
require.NoError(t, err)
require.Equal(t, &Router{
context: context.Background(),
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: DefaultJSONDocumentationPath,
yamlDocumentationPath: DefaultYAMLDocumentationPath,
@@ -53,7 +54,7 @@ func TestNewRouter(t *testing.T) {
t.Run("ok - with custom context", func(t *testing.T) {
type key struct{}
ctx := context.WithValue(context.Background(), key{}, "value")
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
})
@@ -61,7 +62,7 @@ func TestNewRouter(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &Router{
context: ctx,
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: DefaultJSONDocumentationPath,
yamlDocumentationPath: DefaultYAMLDocumentationPath,
@@ -71,7 +72,7 @@ func TestNewRouter(t *testing.T) {
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{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "/json/path",
@@ -81,7 +82,7 @@ func TestNewRouter(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &Router{
context: ctx,
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: "/json/path",
yamlDocumentationPath: "/yaml/path",
@@ -91,7 +92,7 @@ func TestNewRouter(t *testing.T) {
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{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "json/path",
@@ -105,7 +106,7 @@ func TestNewRouter(t *testing.T) {
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{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "/json/path",
@@ -315,6 +316,97 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
require.NoError(t, err)
require.YAMLEq(t, string(expected), body, string(body))
})
t.Run("ok - subrouter", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
Version: "test swagger version",
},
},
JSONDocumentationPath: "/custom/path",
})
require.NoError(t, err)
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
mSubRouter := mRouter.PathPrefix("/prefix").Subrouter()
subrouter, err := router.SubRouter(apirouter.NewGorillaMuxRouter(mSubRouter), SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subrouter.AddRoute(http.MethodGet, "/taz", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
require.NoError(t, err)
t.Run("add route with path equal to prefix path", func(t *testing.T) {
_, err = subrouter.AddRoute(http.MethodGet, "", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
require.NoError(t, err)
})
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)
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
body := readBody(t, w.Result().Body)
actual, err := ioutil.ReadFile("testdata/subrouter.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
})
t.Run("ok - new router with path prefix", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
Version: "test swagger version",
},
},
JSONDocumentationPath: "/custom/path",
PathPrefix: "/prefix",
})
require.NoError(t, err)
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
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)
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
body := readBody(t, w.Result().Body)
actual, err := ioutil.ReadFile("testdata/router_with_prefix.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
})
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {

View File

@@ -3,6 +3,7 @@ package swagger
import (
"errors"
"fmt"
"path"
"sort"
"github.com/alecthomas/jsonschema"
@@ -23,7 +24,7 @@ var (
// AddRawRoute add route to router with specific method, path and handler. Add the
// router also to the swagger schema, after validating it
func (r Router) AddRawRoute(method string, path string, handler apirouter.HandlerFunc, operation Operation) (interface{}, error) {
func (r Router) AddRawRoute(method string, routePath string, handler apirouter.HandlerFunc, operation Operation) (interface{}, error) {
op := operation.Operation
if op != nil {
err := operation.Validate(r.context)
@@ -36,10 +37,11 @@ func (r Router) AddRawRoute(method string, path string, handler apirouter.Handle
op.Responses = openapi3.NewResponses()
}
}
r.swaggerSchema.AddOperation(path, method, op)
pathWithPrefix := path.Join(r.pathPrefix, routePath)
r.swaggerSchema.AddOperation(pathWithPrefix, method, op)
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
return r.router.AddRoute(path, method, handler), nil
return r.router.AddRoute(pathWithPrefix, method, handler), nil
}
// Content is the type of a content.

19
testdata/router_with_prefix.json vendored Normal file
View File

@@ -0,0 +1,19 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/prefix/foo": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
}
}
}

37
testdata/subrouter.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/foo": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
},
"/prefix/taz": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
},
"/prefix": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
}
}
}