mirror of
https://github.com/davidebianchi/gswagger.git
synced 2026-01-17 03:28:31 -05:00
Compare commits
103 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24dfb293ea | ||
|
|
a5b9bd3dc4 | ||
|
|
7f7c92eaca | ||
|
|
9fac38a162 | ||
|
|
424779a7d8 | ||
|
|
d6a528ea28 | ||
|
|
909c58608a | ||
|
|
43c6e37a47 | ||
|
|
b9dc8ff83c | ||
|
|
1b95853d11 | ||
|
|
e8369933fc | ||
|
|
89d668771a | ||
|
|
0039a3f74f | ||
|
|
b29887d15f | ||
|
|
e03aeb51c2 | ||
|
|
a3cb8e3775 | ||
|
|
995c3d97a2 | ||
|
|
d376b5411e | ||
|
|
b187bd716f | ||
|
|
d07b9c96f5 | ||
|
|
3c8cffc622 | ||
|
|
c5e3219f7a | ||
|
|
d9c105585b | ||
|
|
3f7d09cc36 | ||
|
|
57842cf39d | ||
|
|
3e359451c8 | ||
|
|
7896d8efd3 | ||
|
|
ac9ae09ff9 | ||
|
|
42bfc9c9a6 | ||
|
|
32233b0a6b | ||
|
|
ab052edbe2 | ||
|
|
90b7305b57 | ||
|
|
0a6ddb22c3 | ||
|
|
e884893fd5 | ||
|
|
1aaf503686 | ||
|
|
f109edd60a | ||
|
|
d187894847 | ||
|
|
6eeb5ab409 | ||
|
|
8efc400a2f | ||
|
|
5c5d02c68e | ||
|
|
e5b47a772a | ||
|
|
fa6f33399b | ||
|
|
786a5ed67d | ||
|
|
8f8ca16724 | ||
|
|
e1e3e95d80 | ||
|
|
1f550922b6 | ||
|
|
55cfa361ce | ||
|
|
0c867d2839 | ||
|
|
68fdf59cdb | ||
|
|
ebb8822041 | ||
|
|
491f683807 | ||
|
|
122be38154 | ||
|
|
a0ea89ed92 | ||
|
|
f21942de1b | ||
|
|
b1b7025862 | ||
|
|
3d21dece34 | ||
|
|
715c554482 | ||
|
|
d35432abaf | ||
|
|
ffb0e6b3f7 | ||
|
|
94abd8f4bf | ||
|
|
7232d5d823 | ||
|
|
b26ddbeecf | ||
|
|
3374e2bd80 | ||
|
|
33d81e9cdd | ||
|
|
a7a671be5a | ||
|
|
239a70a1a0 | ||
|
|
8c0aacb68c | ||
|
|
d145c6ca5d | ||
|
|
a8c5be8870 | ||
|
|
8fda85d9d3 | ||
|
|
a872dd02b7 | ||
|
|
7615365291 | ||
|
|
6411ef6e66 | ||
|
|
49fd48c375 | ||
|
|
9f3698cf59 | ||
|
|
98ed6678e6 | ||
|
|
0075df7fc4 | ||
|
|
66b593f3f6 | ||
|
|
30bf3ec60e | ||
|
|
ff30e87701 | ||
|
|
07568cabc0 | ||
|
|
2cffb94971 | ||
|
|
ec86fe1571 | ||
|
|
5d1b1b795d | ||
|
|
b964b3c3ca | ||
|
|
4e8ccbd66d | ||
|
|
9aaf041909 | ||
|
|
b1dc480411 | ||
|
|
3d9ad0fb5f | ||
|
|
5f07fcb394 | ||
|
|
985e3dfd03 | ||
|
|
67073bb3bb | ||
|
|
ba069411b1 | ||
|
|
a950dcc879 | ||
|
|
1fe64517bd | ||
|
|
651f2d0478 | ||
|
|
22cf8cdbc4 | ||
|
|
2d310b15e1 | ||
|
|
b77a71d0e4 | ||
|
|
7f240250d5 | ||
|
|
3b0f5b33eb | ||
|
|
6c8a4b5cdf | ||
|
|
04774f8ed5 |
7
.github/dependabot.yml
vendored
Normal file
7
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: gomod
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: daily
|
||||
open-pull-requests-limit: 10
|
||||
55
.github/workflows/test-builds.yml
vendored
55
.github/workflows/test-builds.yml
vendored
@@ -5,28 +5,35 @@ on:
|
||||
push:
|
||||
jobs:
|
||||
tests:
|
||||
name: Test on go ${{ matrix.go_version }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go_version: [1.15]
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use golang ${{ matrix.go_version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go_version }}
|
||||
name: Test on go ${{ matrix.go_version }} os ${{ matrix.os }}
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
go_version: [1.16, 1.17]
|
||||
os: [ubuntu-latest]
|
||||
include:
|
||||
- go_version: 1.17
|
||||
os: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Use golang ${{ matrix.go_version }}
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: ${{ matrix.go_version }}
|
||||
|
||||
- name: Go version
|
||||
run: |
|
||||
go version
|
||||
- name: Go get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
- name: Run tests
|
||||
run: |
|
||||
go test ./... -count=1 -race -cover
|
||||
- name: Build
|
||||
run: |
|
||||
go build -v .
|
||||
- name: Go version
|
||||
run: |
|
||||
go version
|
||||
- name: Go get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
- name: Run tests
|
||||
run: |
|
||||
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
|
||||
|
||||
84
CHANGELOG.md
Normal file
84
CHANGELOG.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# Changelog
|
||||
|
||||
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).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.6.0 - 04-11-2022
|
||||
|
||||
### Added
|
||||
|
||||
- Tags support to `router.AddRoute` accepted definition
|
||||
|
||||
## 0.5.1 - 03-10-2022
|
||||
|
||||
### Fixed
|
||||
|
||||
- upgrade deps
|
||||
|
||||
## v0.5.0 - 05-08-2022
|
||||
|
||||
### Added
|
||||
|
||||
- path params are auto generated if not set
|
||||
|
||||
## v0.4.0 - 02-08-2022
|
||||
|
||||
### Changed
|
||||
|
||||
- change jsonschema lib to `invopop/jsonschema v0.5.0`. This updates remove the `additionalProperties: true` from all the schemas, as it is the default value
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- modified Router interface by sorting addRoute arguments in a different manner: first method and then path
|
||||
To migrate, all the router implementation must be updated with the Router interface change.
|
||||
|
||||
Before:
|
||||
|
||||
```go
|
||||
type Router interface {
|
||||
AddRoute(path, method string, handler HandlerFunc) Route
|
||||
}
|
||||
```
|
||||
|
||||
After:
|
||||
|
||||
```go
|
||||
type Router interface {
|
||||
AddRoute(method, path string, handler HandlerFunc) Route
|
||||
}
|
||||
```
|
||||
|
||||
### Updates
|
||||
|
||||
- kin-openapi@v0.98.0
|
||||
- go-openapi/swag@v0.21.1
|
||||
- labstack/echo/v4@v4.7.2
|
||||
|
||||
## 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
|
||||
|
||||
Introduced the `apirouter.Router` interface, which abstract the used router.
|
||||
Changed function are:
|
||||
|
||||
- Router struct now support `apirouter.Router` interface
|
||||
- NewRouter function accepted router is an `apirouter.Router`
|
||||
- AddRawRoute now accept `apirouter.Handler` iterface
|
||||
- AddRawRoute returns an interface instead of *mux.Router. This interface is the Route returned by specific Router
|
||||
- AddRoute now accept `apirouter.Handler` iterface
|
||||
- AddRoute returns an interface instead of *mux.Router. This interface is the Route returned by specific Router
|
||||
|
||||
## v0.1.0
|
||||
|
||||
Initial release
|
||||
24
Makefile
Normal file
24
Makefile
Normal file
@@ -0,0 +1,24 @@
|
||||
VERSION ?= latest
|
||||
|
||||
# Create a variable that contains the current date in UTC
|
||||
# Different flow if this script is running on Darwin or Linux machines.
|
||||
ifeq (Darwin,$(shell uname))
|
||||
NOW_DATE = $(shell date -u +%d-%m-%Y)
|
||||
else
|
||||
NOW_DATE = $(shell date -u -I)
|
||||
endif
|
||||
|
||||
all: test
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
go test ./... -coverprofile coverage.out
|
||||
$(MAKE) clean
|
||||
|
||||
.PHONY: version
|
||||
version:
|
||||
sed -i.bck "s|## Unreleased|## Unreleased\n\n## ${VERSION} - ${NOW_DATE}|g" "CHANGELOG.md"
|
||||
rm -fr "CHANGELOG.md.bck"
|
||||
git add "CHANGELOG.md"
|
||||
git commit -m "Upgrade version to v${VERSION}"
|
||||
git tag v${VERSION}
|
||||
108
README.md
108
README.md
@@ -1,34 +1,43 @@
|
||||
<div align="center">
|
||||
|
||||
|
||||
[![Build Status][github-actions-svg]][github-actions]
|
||||
[](https://coveralls.io/github/davidebianchi/gswagger?branch=main)
|
||||
[![Go Report Card][go-report-card]][go-report-card-link]
|
||||
[![GoDoc][godoc-svg]][godoc-link]
|
||||
|
||||
# Gorilla Swagger
|
||||
# gswagger
|
||||
|
||||
</div>
|
||||
|
||||
Generate a swagger dynamically based on the types used to handle request and response.
|
||||
Generate an openapi spec dynamically based on the types used to handle request and response.
|
||||
|
||||
It works with [gorilla-mux](https://github.com/gorilla/mux) and uses [kin-openapi]
|
||||
to automatically generate and serve a swagger file.
|
||||
It works with any router which support handler net/http HandlerFunc compatible.
|
||||
|
||||
The routers supported out of the box are:
|
||||
|
||||
- [gorilla-mux](https://github.com/gorilla/mux)
|
||||
|
||||
This lib uses [kin-openapi] to automatically generate and serve a swagger file.
|
||||
|
||||
To convert struct to schemas, we use [jsonschema] library.
|
||||
The struct must contains the appropriate struct tags to be inserted in json schema to generate the schema dynamically.
|
||||
It is always possible to add a totally custom swagger schema using [kin-openapi]
|
||||
It is always possible to add a totally custom swagger schema using [kin-openapi].
|
||||
|
||||
## Usage
|
||||
|
||||
An example usage of this lib:
|
||||
To add a router not handled out of the box, it must implements the [Router interface](./apirouter/router.go).
|
||||
|
||||
An example usage of this lib with gorilla mux:
|
||||
|
||||
```go
|
||||
context := context.Background()
|
||||
r := mux.NewRouter()
|
||||
router, _ := swagger.NewRouter(r, gswagger.Options{
|
||||
muxRouter := mux.NewRouter()
|
||||
|
||||
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), swagger.Options{
|
||||
Context: context,
|
||||
Openapi: &openapi3.Swagger{
|
||||
Openapi: &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: "my swagger title",
|
||||
Title: "my title",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
@@ -39,20 +48,31 @@ okHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Write([]byte("OK"))
|
||||
}
|
||||
|
||||
router.AddRoute(http.MethodPost, "/users", okHandler, Definitions{
|
||||
RequestBody: &gswagger.ContentValue{
|
||||
Content: gswagger.Content{
|
||||
type User struct {
|
||||
Name string `json:"name" jsonschema:"title=The user name,required" jsonschema_extras:"example=Jane"`
|
||||
PhoneNumber int `json:"phone" jsonschema:"title=mobile number of user"`
|
||||
Groups []string `json:"groups,omitempty" jsonschema:"title=groups of the user,default=users"`
|
||||
Address string `json:"address" jsonschema:"title=user address"`
|
||||
}
|
||||
type Users []User
|
||||
type errorResponse struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
router.AddRoute(http.MethodPost, "/users", okHandler, swagger.Definitions{
|
||||
RequestBody: &swagger.ContentValue{
|
||||
Content: swagger.Content{
|
||||
"application/json": {Value: User{}},
|
||||
},
|
||||
},
|
||||
Responses: map[int]gswagger.ContentValue{
|
||||
Responses: map[int]swagger.ContentValue{
|
||||
201: {
|
||||
Content: gswagger.Content{
|
||||
Content: swagger.Content{
|
||||
"text/html": {Value: ""},
|
||||
},
|
||||
},
|
||||
401: {
|
||||
Content: gswagger.Content{
|
||||
Content: swagger.Content{
|
||||
"application/json": {Value: &errorResponse{}},
|
||||
},
|
||||
Description: "invalid request",
|
||||
@@ -60,11 +80,11 @@ router.AddRoute(http.MethodPost, "/users", okHandler, Definitions{
|
||||
},
|
||||
})
|
||||
|
||||
router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
|
||||
Responses: map[int]ContentValue{
|
||||
router.AddRoute(http.MethodGet, "/users", okHandler, swagger.Definitions{
|
||||
Responses: map[int]swagger.ContentValue{
|
||||
200: {
|
||||
Content: Content{
|
||||
"application/json": {Value: &Users{}},
|
||||
Content: swagger.Content{
|
||||
"application/json": {Value: &[]User{}},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -81,7 +101,46 @@ operation.AddRequestBody(requestBody)
|
||||
router.AddRawRoute(http.MethodPost, "/cars", okHandler, operation)
|
||||
```
|
||||
|
||||
This configuration will output the schema shown [here](testdata/users_employees.json)
|
||||
This configuration will output the schema shown [here](testdata/users_employees.json).
|
||||
|
||||
## Auto generated path params schema
|
||||
|
||||
The path params, if not set in schema, are auto generated from the path. Currently, it is supported only the path params like `{myPath}`.
|
||||
|
||||
For example, with this use case:
|
||||
|
||||
```golang
|
||||
okHandler := func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("OK"))
|
||||
}
|
||||
|
||||
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
|
||||
Querystring: ParameterValue{
|
||||
"query": {
|
||||
Schema: &Schema{Value: ""},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = router.AddRoute(http.MethodGet, "/cars/{carId}/drivers/{driverId}", okHandler, Definitions{})
|
||||
require.NoError(t, err)
|
||||
```
|
||||
|
||||
The generated oas schema will contains `userId`, `carId` and `driverId` as path params set to string.
|
||||
If only one params is set, you must specify manually all the path params.
|
||||
|
||||
The generated file for this test case is [here](./testdata/params-autofill.json).
|
||||
|
||||
## SubRouter
|
||||
|
||||
It is possible to create a new sub router from the swagger.Router.
|
||||
It is possible to add a prefix to all the routes created under the specific router (instead of use the router specific methods, if given, or repeat the prefix for every route).
|
||||
|
||||
It could also be useful if you need a sub router to create a group of APIs which use the same middleware (for example,this could be achieved by the SubRouter features of gorilla mux, for example).
|
||||
|
||||
To see the SubRouter example, please see the [SubRouter test](./integration_test.go).
|
||||
|
||||
### FAQ
|
||||
|
||||
@@ -101,7 +160,7 @@ You can create manually a swagger with `oneOf` using the `AddRawRoute` method, o
|
||||
|
||||
*Formats*:
|
||||
|
||||
* `uuid` is unsupported by [kin-openapi]
|
||||
- `uuid` is unsupported by [kin-openapi]
|
||||
|
||||
## Versioning
|
||||
|
||||
@@ -110,10 +169,11 @@ see the [tags on this repository](https://github.com/davidebianchi/gswagger/tags
|
||||
|
||||
<!-- Reference -->
|
||||
[kin-openapi]: https://github.com/getkin/kin-openapi
|
||||
[jsonschema]: https://github.com/alecthomas/jsonschema
|
||||
[jsonschema]: https://github.com/invopop/jsonschemaa
|
||||
[github-actions]: https://github.com/davidebianchi/gswagger/actions
|
||||
[github-actions-svg]: https://github.com/davidebianchi/gswagger/workflows/Test%20and%20build/badge.svg
|
||||
[godoc-svg]: https://godoc.org/github.com/davidebianchi/gswagger?status.svg
|
||||
[godoc-link]: https://godoc.org/github.com/davidebianchi/gswagger
|
||||
[go-report-card]: https://goreportcard.com/badge/github.com/davidebianchi/gswagger
|
||||
[go-report-card-link]: https://goreportcard.com/report/github.com/davidebianchi/gswagger
|
||||
[semver]: https://semver.org/
|
||||
|
||||
17
apirouter/gorilla.go
Normal file
17
apirouter/gorilla.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package apirouter
|
||||
|
||||
import "github.com/gorilla/mux"
|
||||
|
||||
type gorillaRouter struct {
|
||||
router *mux.Router
|
||||
}
|
||||
|
||||
func (r gorillaRouter) AddRoute(method string, path string, handler HandlerFunc) Route {
|
||||
return r.router.HandleFunc(path, handler).Methods(method)
|
||||
}
|
||||
|
||||
func NewGorillaMuxRouter(router *mux.Router) Router {
|
||||
return gorillaRouter{
|
||||
router: router,
|
||||
}
|
||||
}
|
||||
47
apirouter/gorilla_test.go
Normal file
47
apirouter/gorilla_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package apirouter
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGorillaMuxRouter(t *testing.T) {
|
||||
muxRouter := mux.NewRouter()
|
||||
ar := NewGorillaMuxRouter(muxRouter)
|
||||
|
||||
t.Run("create a new api router", func(t *testing.T) {
|
||||
require.Implements(t, (*Router)(nil), ar)
|
||||
})
|
||||
|
||||
t.Run("add new route", func(t *testing.T) {
|
||||
route := ar.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(200)
|
||||
w.Write(nil)
|
||||
})
|
||||
|
||||
_, ok := route.(*mux.Route)
|
||||
require.True(t, ok)
|
||||
|
||||
t.Run("router exposes correctly api", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/foo", nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
})
|
||||
|
||||
t.Run("router exposes api only to the specific method", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodPost, "/foo", nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusMethodNotAllowed, w.Result().StatusCode)
|
||||
})
|
||||
})
|
||||
}
|
||||
12
apirouter/router.go
Normal file
12
apirouter/router.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package apirouter
|
||||
|
||||
import "net/http"
|
||||
|
||||
// Handler is the http type handler
|
||||
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
|
||||
|
||||
type Router interface {
|
||||
AddRoute(method string, path string, handler HandlerFunc) Route
|
||||
}
|
||||
|
||||
type Route interface{}
|
||||
33
go.mod
33
go.mod
@@ -1,13 +1,34 @@
|
||||
module github.com/davidebianchi/gswagger
|
||||
|
||||
go 1.15
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add
|
||||
github.com/getkin/kin-openapi v0.35.0
|
||||
github.com/getkin/kin-openapi v0.103.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-openapi/swag v0.19.13 // indirect
|
||||
github.com/go-openapi/swag v0.21.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/iancoleman/orderedmap v0.1.0 // indirect
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/iancoleman/orderedmap v0.2.0 // indirect
|
||||
github.com/invopop/jsonschema v0.6.0
|
||||
github.com/labstack/echo/v4 v4.9.0
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/stretchr/testify v1.8.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/invopop/yaml v0.2.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/labstack/gommon v0.3.1 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc // indirect
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
82
go.sum
82
go.sum
@@ -1,26 +1,27 @@
|
||||
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add h1:UWj2AVW7oygpatGgJRy6rvNBcl+J7u8vl6qTV+XNWzA=
|
||||
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/getkin/kin-openapi v0.35.0 h1:YoJusew7Es36hSpnEx3gRL2DGj/82T3j3Akbs9VIXDQ=
|
||||
github.com/getkin/kin-openapi v0.35.0/go.mod h1:ZJSfy1PxJv2QQvH9EdBj3nupRTVvV42mkW6zKUlRBwk=
|
||||
github.com/getkin/kin-openapi v0.103.0 h1:F5wAtaQvPWxKCAYZ69LgHAThgu16p4u41VQtbn1U8LA=
|
||||
github.com/getkin/kin-openapi v0.103.0/go.mod h1:w4lRPHiyOdwGbOkLIyk+P0qCwlu7TXPCHD/64nSXzgE=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.13 h1:233UVgMy1DlmCYYfOiFpta6e2urloh+sEs5id6lyzog=
|
||||
github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
|
||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
|
||||
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||
github.com/iancoleman/orderedmap v0.1.0 h1:2orAxZBJsvimgEBmMWfXaFlzSG2fbQil5qzP3F6cCkg=
|
||||
github.com/iancoleman/orderedmap v0.1.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
|
||||
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||
github.com/invopop/jsonschema v0.6.0 h1:8e+xY8ZEn8gDHUYylSlLHy22P+SLeIRIHv3nM3hCbmY=
|
||||
github.com/invopop/jsonschema v0.6.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
|
||||
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
|
||||
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -28,34 +29,73 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
|
||||
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
|
||||
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
|
||||
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
|
||||
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc h1:i6Z9eOQAdM7lvsbkT3fwFNtSAAC+A59TYilFj53HW+E=
|
||||
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package swagger
|
||||
package swagger_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -8,8 +8,11 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
swagger "github.com/davidebianchi/gswagger"
|
||||
"github.com/davidebianchi/gswagger/apirouter"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/labstack/echo/v4"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -20,7 +23,7 @@ const (
|
||||
|
||||
func TestIntegration(t *testing.T) {
|
||||
t.Run("router works correctly", func(t *testing.T) {
|
||||
muxRouter := setupSwagger(t)
|
||||
muxRouter, _ := setupSwagger(t)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
|
||||
@@ -34,7 +37,7 @@ func TestIntegration(t *testing.T) {
|
||||
|
||||
t.Run("and generate swagger", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
|
||||
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
@@ -44,6 +47,125 @@ func TestIntegration(t *testing.T) {
|
||||
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("router works correctly - echo", func(t *testing.T) {
|
||||
echoRouter, _ := setupEchoSwagger(t)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
|
||||
|
||||
echoRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "OK", body)
|
||||
|
||||
t.Run("and generate swagger", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
|
||||
|
||||
echoRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("works correctly with subrouter - handles path prefix - gorilla mux", func(t *testing.T) {
|
||||
muxRouter, swaggerRouter := setupSwagger(t)
|
||||
|
||||
muxSubRouter := muxRouter.NewRoute().Subrouter()
|
||||
subRouter, err := swaggerRouter.SubRouter(apirouter.NewGorillaMuxRouter(muxSubRouter), swagger.SubRouterOptions{
|
||||
PathPrefix: "/prefix",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "OK", body)
|
||||
|
||||
t.Run("correctly call sub router", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/prefix/foo", nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "OK", body)
|
||||
})
|
||||
|
||||
t.Run("and generate swagger", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
|
||||
|
||||
muxRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("works correctly with subrouter - handles path prefix - echo", func(t *testing.T) {
|
||||
eRouter, swaggerRouter := setupEchoSwagger(t)
|
||||
|
||||
subRouter, err := swaggerRouter.SubRouter(echoRouter{router: eRouter}, swagger.SubRouterOptions{
|
||||
PathPrefix: "/prefix",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
|
||||
|
||||
eRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "OK", body)
|
||||
|
||||
t.Run("correctly call sub router", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, "/prefix/foo", nil)
|
||||
|
||||
eRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "OK", body)
|
||||
})
|
||||
|
||||
t.Run("and generate swagger", func(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
|
||||
|
||||
eRouter.ServeHTTP(w, r)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Result().StatusCode)
|
||||
|
||||
body := readBody(t, w.Result().Body)
|
||||
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func readBody(t *testing.T, requestBody io.ReadCloser) string {
|
||||
@@ -55,15 +177,15 @@ func readBody(t *testing.T, requestBody io.ReadCloser) string {
|
||||
return string(body)
|
||||
}
|
||||
|
||||
func setupSwagger(t *testing.T) *mux.Router {
|
||||
func setupSwagger(t *testing.T) (*mux.Router, *swagger.Router) {
|
||||
t.Helper()
|
||||
|
||||
context := context.Background()
|
||||
muxRouter := mux.NewRouter()
|
||||
|
||||
router, err := NewRouter(muxRouter, Options{
|
||||
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), swagger.Options{
|
||||
Context: context,
|
||||
Openapi: &openapi3.Swagger{
|
||||
Openapi: &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: swaggerOpenapiTitle,
|
||||
Version: swaggerOpenapiVersion,
|
||||
@@ -72,17 +194,61 @@ func setupSwagger(t *testing.T) *mux.Router {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
handler := func(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`OK`))
|
||||
}
|
||||
operation := Operation{}
|
||||
operation := swagger.Operation{}
|
||||
|
||||
_, err = router.AddRawRoute(http.MethodGet, "/hello", handler, operation)
|
||||
_, err = router.AddRawRoute(http.MethodGet, "/hello", okHandler, operation)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
|
||||
return muxRouter
|
||||
return muxRouter, router
|
||||
}
|
||||
|
||||
func okHandler(w http.ResponseWriter, req *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`OK`))
|
||||
}
|
||||
|
||||
func setupEchoSwagger(t *testing.T) (*echo.Echo, *swagger.Router) {
|
||||
t.Helper()
|
||||
|
||||
context := context.Background()
|
||||
e := echo.New()
|
||||
|
||||
router, err := swagger.NewRouter(echoRouter{router: e}, swagger.Options{
|
||||
Context: context,
|
||||
Openapi: &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: swaggerOpenapiTitle,
|
||||
Version: swaggerOpenapiVersion,
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
operation := swagger.Operation{}
|
||||
|
||||
_, err = router.AddRawRoute(http.MethodGet, "/hello", func(w http.ResponseWriter, req *http.Request) {
|
||||
ctx := e.NewContext(req, w)
|
||||
echoOkHandler(ctx)
|
||||
}, operation)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
|
||||
return e, router
|
||||
}
|
||||
|
||||
func echoOkHandler(c echo.Context) error {
|
||||
return c.String(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
type echoRouter struct {
|
||||
router *echo.Echo
|
||||
}
|
||||
|
||||
func (r echoRouter) AddRoute(method, path string, handler apirouter.HandlerFunc) apirouter.Route {
|
||||
return r.router.Add(method, path, echo.WrapHandler(http.HandlerFunc(handler)))
|
||||
}
|
||||
|
||||
43
main.go
43
main.go
@@ -7,9 +7,9 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/davidebianchi/gswagger/apirouter"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -27,27 +27,32 @@ const (
|
||||
defaultOpenapiVersion = "3.0.0"
|
||||
)
|
||||
|
||||
// Router handle the gorilla mux router and the swagger schema
|
||||
// Router handle the api router and the swagger schema.
|
||||
// api router supported out of the box are:
|
||||
// - gorilla mux
|
||||
type Router struct {
|
||||
router *mux.Router
|
||||
swaggerSchema *openapi3.Swagger
|
||||
router apirouter.Router
|
||||
swaggerSchema *openapi3.T
|
||||
context context.Context
|
||||
jsonDocumentationPath string
|
||||
yamlDocumentationPath string
|
||||
pathPrefix string
|
||||
}
|
||||
|
||||
// Options to be passed to create the new router and swagger
|
||||
type Options struct {
|
||||
Context context.Context
|
||||
Openapi *openapi3.Swagger
|
||||
Openapi *openapi3.T
|
||||
// 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
|
||||
// Add path prefix to add to every router path.
|
||||
PathPrefix string
|
||||
}
|
||||
|
||||
// NewRouter generate new router with swagger. Default to OpenAPI 3.0.0
|
||||
func NewRouter(router *mux.Router, options Options) (*Router, error) {
|
||||
func NewRouter(router apirouter.Router, options Options) (*Router, error) {
|
||||
swagger, err := generateNewValidSwagger(options.Openapi)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrValidatingSwagger, err)
|
||||
@@ -80,10 +85,26 @@ func NewRouter(router *mux.Router, options Options) (*Router, error) {
|
||||
context: ctx,
|
||||
yamlDocumentationPath: yamlDocumentationPath,
|
||||
jsonDocumentationPath: jsonDocumentationPath,
|
||||
pathPrefix: options.PathPrefix,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func generateNewValidSwagger(swagger *openapi3.Swagger) (*openapi3.Swagger, error) {
|
||||
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
|
||||
}
|
||||
|
||||
func generateNewValidSwagger(swagger *openapi3.T) (*openapi3.T, error) {
|
||||
if swagger == nil {
|
||||
return nil, fmt.Errorf("swagger is required")
|
||||
}
|
||||
@@ -118,21 +139,21 @@ func (r Router) GenerateAndExposeSwagger() error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w json marshal: %s", ErrGenerateSwagger, err)
|
||||
}
|
||||
r.router.HandleFunc(r.jsonDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
r.router.AddRoute(http.MethodGet, r.jsonDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(jsonSwagger)
|
||||
}).Methods(http.MethodGet)
|
||||
})
|
||||
|
||||
yamlSwagger, err := yaml.JSONToYAML(jsonSwagger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%w yaml marshal: %s", ErrGenerateSwagger, err)
|
||||
}
|
||||
r.router.HandleFunc(r.yamlDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
r.router.AddRoute(http.MethodGet, r.yamlDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write(yamlSwagger)
|
||||
}).Methods(http.MethodGet)
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
161
main_test.go
161
main_test.go
@@ -3,45 +3,48 @@ package swagger
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/davidebianchi/gswagger/apirouter"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestNewRouter(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
muxRouter := mux.NewRouter()
|
||||
mAPIRouter := apirouter.NewGorillaMuxRouter(muxRouter)
|
||||
|
||||
info := &openapi3.Info{
|
||||
Title: "my title",
|
||||
Version: "my version",
|
||||
}
|
||||
openapi := &openapi3.Swagger{
|
||||
openapi := &openapi3.T{
|
||||
Info: info,
|
||||
Paths: openapi3.Paths{},
|
||||
}
|
||||
|
||||
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,
|
||||
@@ -51,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,
|
||||
})
|
||||
@@ -59,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,
|
||||
@@ -69,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",
|
||||
@@ -79,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",
|
||||
@@ -89,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",
|
||||
@@ -103,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",
|
||||
@@ -117,7 +120,7 @@ func TestNewRouter(t *testing.T) {
|
||||
|
||||
func TestGenerateValidSwagger(t *testing.T) {
|
||||
t.Run("not ok - empty swagger info", func(t *testing.T) {
|
||||
swagger := &openapi3.Swagger{}
|
||||
swagger := &openapi3.T{}
|
||||
|
||||
swagger, err := generateNewValidSwagger(swagger)
|
||||
require.Nil(t, swagger)
|
||||
@@ -125,7 +128,7 @@ func TestGenerateValidSwagger(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("not ok - empty info title", func(t *testing.T) {
|
||||
swagger := &openapi3.Swagger{
|
||||
swagger := &openapi3.T{
|
||||
Info: &openapi3.Info{},
|
||||
}
|
||||
|
||||
@@ -135,7 +138,7 @@ func TestGenerateValidSwagger(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("not ok - empty info version", func(t *testing.T) {
|
||||
swagger := &openapi3.Swagger{
|
||||
swagger := &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: "title",
|
||||
},
|
||||
@@ -147,7 +150,7 @@ func TestGenerateValidSwagger(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("ok - custom swagger", func(t *testing.T) {
|
||||
swagger := &openapi3.Swagger{
|
||||
swagger := &openapi3.T{
|
||||
Info: &openapi3.Info{},
|
||||
}
|
||||
|
||||
@@ -167,13 +170,13 @@ func TestGenerateValidSwagger(t *testing.T) {
|
||||
Title: "my title",
|
||||
Version: "my version",
|
||||
}
|
||||
swagger := &openapi3.Swagger{
|
||||
swagger := &openapi3.T{
|
||||
Info: info,
|
||||
}
|
||||
|
||||
swagger, err := generateNewValidSwagger(swagger)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, &openapi3.Swagger{
|
||||
require.Equal(t, &openapi3.T{
|
||||
OpenAPI: defaultOpenapiVersion,
|
||||
Info: info,
|
||||
Paths: openapi3.Paths{},
|
||||
@@ -184,8 +187,8 @@ func TestGenerateValidSwagger(t *testing.T) {
|
||||
func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
t.Run("fails swagger validation", func(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
Openapi: &openapi3.Swagger{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
|
||||
Openapi: &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: "title",
|
||||
Version: "version",
|
||||
@@ -207,12 +210,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
t.Run("correctly expose json documentation from loaded swagger file", func(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
|
||||
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
|
||||
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
|
||||
Openapi: swagger,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
@@ -233,13 +237,14 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
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")
|
||||
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
|
||||
Openapi: swagger,
|
||||
JSONDocumentationPath: "/custom/path",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
@@ -260,12 +265,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
t.Run("correctly expose yaml documentation from loaded swagger file", func(t *testing.T) {
|
||||
mRouter := mux.NewRouter()
|
||||
|
||||
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
|
||||
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
|
||||
Openapi: swagger,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
@@ -286,13 +292,14 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
|
||||
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")
|
||||
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
|
||||
require.NoError(t, err)
|
||||
|
||||
router, err := NewRouter(mRouter, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
|
||||
Openapi: swagger,
|
||||
YAMLDocumentationPath: "/custom/path",
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
err = router.GenerateAndExposeSwagger()
|
||||
require.NoError(t, err)
|
||||
@@ -309,4 +316,104 @@ 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 {
|
||||
t.Helper()
|
||||
|
||||
body, err := ioutil.ReadAll(requestBody)
|
||||
require.NoError(t, err)
|
||||
|
||||
return string(body)
|
||||
}
|
||||
|
||||
57
route.go
57
route.go
@@ -3,12 +3,13 @@ package swagger
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/jsonschema"
|
||||
"github.com/davidebianchi/gswagger/apirouter"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/invopop/jsonschema"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -22,12 +23,9 @@ var (
|
||||
ErrQuerystring = errors.New("errors generating querystring schema")
|
||||
)
|
||||
|
||||
// Handler is the http type handler
|
||||
type Handler func(w http.ResponseWriter, req *http.Request)
|
||||
|
||||
// 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 Handler, operation Operation) (*mux.Route, 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)
|
||||
@@ -40,12 +38,11 @@ func (r Router) AddRawRoute(method string, path string, handler Handler, operati
|
||||
op.Responses = openapi3.NewResponses()
|
||||
}
|
||||
}
|
||||
r.swaggerSchema.AddOperation(path, method, op)
|
||||
pathWithPrefix := path.Join(r.pathPrefix, routePath)
|
||||
r.swaggerSchema.AddOperation(pathWithPrefix, method, op)
|
||||
|
||||
return r.router.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
|
||||
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
|
||||
handler(w, req)
|
||||
}).Methods(method), nil
|
||||
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
|
||||
return r.router.AddRoute(method, pathWithPrefix, handler), nil
|
||||
}
|
||||
|
||||
// Content is the type of a content.
|
||||
@@ -58,14 +55,16 @@ type Schema struct {
|
||||
AllowAdditionalProperties bool
|
||||
}
|
||||
|
||||
// ParameterValue is the struct containing the schema or the content information.
|
||||
// If content is specified, it takes precedence.
|
||||
type ParameterValue map[string]struct {
|
||||
type Parameter struct {
|
||||
Content Content
|
||||
Schema *Schema
|
||||
Description string
|
||||
}
|
||||
|
||||
// ParameterValue is the struct containing the schema or the content information.
|
||||
// If content is specified, it takes precedence.
|
||||
type ParameterValue map[string]Parameter
|
||||
|
||||
// ContentValue is the struct containing the content information.
|
||||
type ContentValue struct {
|
||||
Content Content
|
||||
@@ -74,6 +73,7 @@ type ContentValue struct {
|
||||
|
||||
// Definitions of the route.
|
||||
type Definitions struct {
|
||||
Tags []string
|
||||
PathParams ParameterValue
|
||||
Querystring ParameterValue
|
||||
Headers ParameterValue
|
||||
@@ -90,9 +90,10 @@ const (
|
||||
)
|
||||
|
||||
// AddRoute add a route with json schema inferted by passed schema.
|
||||
func (r Router) AddRoute(method string, path string, handler Handler, schema Definitions) (*mux.Route, error) {
|
||||
func (r Router) AddRoute(method string, path string, handler apirouter.HandlerFunc, schema Definitions) (interface{}, error) {
|
||||
operation := NewOperation()
|
||||
operation.Responses = make(openapi3.Responses)
|
||||
operation.Tags = schema.Tags
|
||||
|
||||
err := r.resolveRequestBodySchema(schema.RequestBody, operation)
|
||||
if err != nil {
|
||||
@@ -104,7 +105,7 @@ func (r Router) AddRoute(method string, path string, handler Handler, schema Def
|
||||
return nil, fmt.Errorf("%w: %s", ErrResponses, err)
|
||||
}
|
||||
|
||||
err = r.resolveParameterSchema(pathParamsType, schema.PathParams, operation)
|
||||
err = r.resolveParameterSchema(pathParamsType, getPathParamsAutofilled(schema, path), operation)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
|
||||
}
|
||||
@@ -135,10 +136,11 @@ func (r Router) getSchemaFromInterface(v interface{}, allowAdditionalProperties
|
||||
reflector := &jsonschema.Reflector{
|
||||
DoNotReference: true,
|
||||
AllowAdditionalProperties: allowAdditionalProperties,
|
||||
Anonymous: true,
|
||||
}
|
||||
|
||||
jsonSchema := reflector.Reflect(v)
|
||||
jsonschema.Version = ""
|
||||
jsonSchema.Version = ""
|
||||
// Empty definitions. Definitions are not valid in openapi3, which use components.
|
||||
// In the future, we could add an option to fill the components in openapi spec.
|
||||
jsonSchema.Definitions = nil
|
||||
@@ -258,3 +260,22 @@ func (r Router) addContentToOASSchema(content Content) (openapi3.Content, error)
|
||||
}
|
||||
return oasContent, nil
|
||||
}
|
||||
|
||||
func getPathParamsAutofilled(schema Definitions, path string) ParameterValue {
|
||||
if schema.PathParams == nil {
|
||||
pathParams := strings.Split(path, "/")
|
||||
for _, param := range pathParams {
|
||||
if strings.HasPrefix(param, "{") && strings.HasSuffix(param, "}") {
|
||||
if schema.PathParams == nil {
|
||||
schema.PathParams = make(ParameterValue)
|
||||
}
|
||||
param = strings.Replace(param, "{", "", 1)
|
||||
param = strings.Replace(param, "}", "", 1)
|
||||
schema.PathParams[param] = Parameter{
|
||||
Schema: &Schema{Value: ""},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return schema.PathParams
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/davidebianchi/gswagger/apirouter"
|
||||
"github.com/getkin/kin-openapi/openapi3"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -183,6 +184,24 @@ func TestAddRoutes(t *testing.T) {
|
||||
testPath: "/users/12",
|
||||
fixturesPath: "testdata/params.json",
|
||||
},
|
||||
{
|
||||
name: "schema without params autofilled",
|
||||
routes: func(t *testing.T, router *Router) {
|
||||
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
|
||||
Querystring: ParameterValue{
|
||||
"query": {
|
||||
Schema: &Schema{Value: ""},
|
||||
},
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = router.AddRoute(http.MethodGet, "/cars/{carId}/drivers/{driverId}", okHandler, Definitions{})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
testPath: "/users/12",
|
||||
fixturesPath: "testdata/params-autofill.json",
|
||||
},
|
||||
{
|
||||
name: "schema with querystring",
|
||||
routes: func(t *testing.T, router *Router) {
|
||||
@@ -403,6 +422,17 @@ func TestAddRoutes(t *testing.T) {
|
||||
testMethod: http.MethodPost,
|
||||
fixturesPath: "testdata/oneOf.json",
|
||||
},
|
||||
{
|
||||
name: "schema with tags",
|
||||
routes: func(t *testing.T, router *Router) {
|
||||
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
|
||||
Tags: []string{"Tag1", "Tag2"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
},
|
||||
testPath: "/users",
|
||||
fixturesPath: "testdata/tags.json",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
@@ -410,7 +440,7 @@ func TestAddRoutes(t *testing.T) {
|
||||
context := context.Background()
|
||||
r := mux.NewRouter()
|
||||
|
||||
router, err := NewRouter(r, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(r), Options{
|
||||
Context: context,
|
||||
Openapi: getBaseSwagger(t),
|
||||
})
|
||||
@@ -589,8 +619,7 @@ func TestResolveRequestBodySchema(t *testing.T) {
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"id": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,7 +630,7 @@ func TestResolveRequestBodySchema(t *testing.T) {
|
||||
}
|
||||
|
||||
mux := mux.NewRouter()
|
||||
router, err := NewRouter(mux, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
|
||||
Openapi: getBaseSwagger(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -744,7 +773,7 @@ func TestResolveResponsesSchema(t *testing.T) {
|
||||
}
|
||||
|
||||
mux := mux.NewRouter()
|
||||
router, err := NewRouter(mux, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
|
||||
Openapi: getBaseSwagger(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -914,7 +943,7 @@ func TestResolveParametersSchema(t *testing.T) {
|
||||
}
|
||||
|
||||
mux := mux.NewRouter()
|
||||
router, err := NewRouter(mux, Options{
|
||||
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
|
||||
Openapi: getBaseSwagger(t),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
@@ -936,13 +965,13 @@ func TestResolveParametersSchema(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func getBaseSwagger(t *testing.T) *openapi3.Swagger {
|
||||
func getBaseSwagger(t *testing.T) *openapi3.T {
|
||||
t.Helper()
|
||||
|
||||
return &openapi3.Swagger{
|
||||
return &openapi3.T{
|
||||
Info: &openapi3.Info{
|
||||
Title: swaggerOpenapiTitle,
|
||||
Version: swaggerOpenapiVersion,
|
||||
Title: "test swagger title",
|
||||
Version: "test swagger version",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
2
testdata/multipart-requestbody.json
vendored
2
testdata/multipart-requestbody.json
vendored
@@ -14,13 +14,11 @@
|
||||
"multipart/form-data": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"address": {
|
||||
"additionalProperties": true,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"street": {
|
||||
|
||||
1
testdata/oneOf.json
vendored
1
testdata/oneOf.json
vendored
@@ -70,7 +70,6 @@
|
||||
"type": "string"
|
||||
},
|
||||
"metadata": {
|
||||
"additionalProperties": true,
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string"
|
||||
|
||||
63
testdata/params-autofill.json
vendored
Normal file
63
testdata/params-autofill.json
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"components": {},
|
||||
"info": {
|
||||
"title": "test swagger title",
|
||||
"version": "test swagger version"
|
||||
},
|
||||
"openapi": "3.0.0",
|
||||
"paths": {
|
||||
"/cars/{carId}/drivers/{driverId}": {
|
||||
"get": {
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "carId",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "path",
|
||||
"name": "driverId",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{userId}": {
|
||||
"get": {
|
||||
"parameters": [
|
||||
{
|
||||
"in": "path",
|
||||
"name": "userId",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
19
testdata/router_with_prefix.json
vendored
Normal file
19
testdata/router_with_prefix.json
vendored
Normal 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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
testdata/schema-no-content.json
vendored
1
testdata/schema-no-content.json
vendored
@@ -32,6 +32,7 @@
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"content": {},
|
||||
"description": "request body without schema"
|
||||
},
|
||||
"responses": {
|
||||
|
||||
37
testdata/subrouter.json
vendored
Normal file
37
testdata/subrouter.json
vendored
Normal 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": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
20
testdata/tags.json
vendored
Normal file
20
testdata/tags.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"components": {},
|
||||
"info": {
|
||||
"title": "test swagger title",
|
||||
"version": "test swagger version"
|
||||
},
|
||||
"openapi": "3.0.0",
|
||||
"paths": {
|
||||
"/users": {
|
||||
"get": {
|
||||
"tags": ["Tag1", "Tag2"],
|
||||
"responses": {
|
||||
"default": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user