48 Commits

Author SHA1 Message Date
Davide Bianchi
34f6bc882e Upgrade version to v0.9.0 2023-04-17 10:25:18 +02:00
Davide Bianchi
bb30bcbb18 Merge pull request #112 from davidebianchi/add-new-oas-fields-to-definition 2023-04-17 10:24:07 +02:00
Davide Bianchi
e3bf8ad397 Merge pull request #111 from davidebianchi/dependabot/go_modules/github.com/gofiber/fiber/v2-2.44.0 2023-04-17 10:21:39 +02:00
Davide Bianchi
36c6f8b159 feat: add new fields to definition struct 2023-04-17 10:20:59 +02:00
dependabot[bot]
4cb82ead72 chore(deps): bump github.com/gofiber/fiber/v2 from 2.43.0 to 2.44.0
Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.43.0 to 2.44.0.
- [Release notes](https://github.com/gofiber/fiber/releases)
- [Commits](https://github.com/gofiber/fiber/compare/v2.43.0...v2.44.0)

---
updated-dependencies:
- dependency-name: github.com/gofiber/fiber/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-17 03:58:01 +00:00
dependabot[bot]
5851dbec22 chore(deps): bump github.com/gofiber/fiber/v2 from 2.42.0 to 2.43.0 (#110)
Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.42.0 to 2.43.0.
- [Release notes](https://github.com/gofiber/fiber/releases)
- [Commits](https://github.com/gofiber/fiber/compare/v2.42.0...v2.43.0)

---
updated-dependencies:
- dependency-name: github.com/gofiber/fiber/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 10:00:45 +02:00
Davide Bianchi
7eabb18dd1 Merge pull request #109 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.115.0
chore(deps): bump github.com/getkin/kin-openapi from 0.114.0 to 0.115.0
2023-03-14 08:33:18 +01:00
dependabot[bot]
b50cc86f43 chore(deps): bump github.com/getkin/kin-openapi from 0.114.0 to 0.115.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.114.0 to 0.115.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.114.0...v0.115.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-14 03:58:20 +00:00
Davide Bianchi
8330d20f23 Merge pull request #108 from malta895/patch-1 2023-03-07 09:34:15 +01:00
Luca Maltagliati
68cc1ddbf1 Add Fiber path parameter example 2023-03-07 09:09:01 +01:00
Davide Bianchi
5f67ad2aad Merge pull request #107 from davidebianchi/upgrade-kin-openapi
update kin-openapi to 0.114.0
2023-03-05 22:10:20 +01:00
Davide Bianchi
0676ab69a8 docs: update CHANGELOG 2023-03-05 21:12:48 +01:00
Davide Bianchi
838f862067 update kin-openapi to 0.114.0 2023-03-05 21:12:34 +01:00
Davide Bianchi
48371417ce Merge pull request #102 from davidebianchi/dependabot/go_modules/github.com/gofiber/fiber/v2-2.42.0 2023-03-05 12:45:09 +01:00
dependabot[bot]
3e11724cd9 chore(deps): bump github.com/gofiber/fiber/v2 from 2.41.0 to 2.42.0
Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.41.0 to 2.42.0.
- [Release notes](https://github.com/gofiber/fiber/releases)
- [Commits](https://github.com/gofiber/fiber/compare/v2.41.0...v2.42.0)

---
updated-dependencies:
- dependency-name: github.com/gofiber/fiber/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-05 11:41:31 +00:00
Davide Bianchi
85a65a69aa Merge pull request #105 from davidebianchi/dependabot/go_modules/github.com/stretchr/testify-1.8.2 2023-03-05 12:40:50 +01:00
dependabot[bot]
0b3a79b0b5 chore(deps): bump github.com/stretchr/testify from 1.8.1 to 1.8.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: github.com/stretchr/testify
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 04:00:09 +00:00
dependabot[bot]
83cb8c6301 chore(deps): bump github.com/labstack/echo/v4 from 4.10.1 to 4.10.2 (#104)
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.10.1 to 4.10.2.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.10.1...v4.10.2)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-22 17:10:45 +01:00
Davide Bianchi
a605011038 Merge pull request #103 from davidebianchi/dependabot/go_modules/github.com/labstack/echo/v4-4.10.1
chore(deps): bump github.com/labstack/echo/v4 from 4.9.1 to 4.10.1
2023-02-21 08:34:57 +01:00
dependabot[bot]
4f18946fab chore(deps): bump github.com/labstack/echo/v4 from 4.9.1 to 4.10.1
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.9.1 to 4.10.1.
- [Release notes](https://github.com/labstack/echo/releases)
- [Changelog](https://github.com/labstack/echo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/labstack/echo/compare/v4.9.1...v4.10.1)

---
updated-dependencies:
- dependency-name: github.com/labstack/echo/v4
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-21 03:57:37 +00:00
Federico Maggi
8ea5444777 Merge pull request #99 from davidebianchi/dependabot/go_modules/github.com/gofiber/fiber/v2-2.41.0
chore(deps): bump github.com/gofiber/fiber/v2 from 2.40.1 to 2.41.0
2023-01-05 07:58:30 +01:00
dependabot[bot]
e6e53be7d8 chore(deps): bump github.com/gofiber/fiber/v2 from 2.40.1 to 2.41.0
Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.40.1 to 2.41.0.
- [Release notes](https://github.com/gofiber/fiber/releases)
- [Commits](https://github.com/gofiber/fiber/compare/v2.40.1...v2.41.0)

---
updated-dependencies:
- dependency-name: github.com/gofiber/fiber/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-04 03:02:29 +00:00
Davide Bianchi
a503dd54db Upgrade version to v0.8.0 2022-12-24 16:31:31 +01:00
Davide Bianchi
231f0b5b65 Merge pull request #97 from davidebianchi/fix-different-params 2022-12-24 16:02:36 +01:00
Davide Bianchi
6d81ef8469 update changelog 2022-12-24 16:00:38 +01:00
Davide Bianchi
f6c98d97cc docs: update CHANGELOG 2022-12-23 21:06:02 +01:00
Davide Bianchi
4587271bc2 fix: fix different params configuration 2022-12-23 21:03:53 +01:00
Davide Bianchi
17f9235abd Merge pull request #95 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.112.0 2022-12-23 10:22:32 +01:00
dependabot[bot]
e81a74c306 chore(deps): bump github.com/getkin/kin-openapi from 0.111.0 to 0.112.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.111.0 to 0.112.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.111.0...v0.112.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-23 03:02:29 +00:00
Davide Bianchi
48e22b5674 Upgrade version to v0.7.0 2022-12-22 19:36:46 +01:00
Davide Bianchi
a1df7c966e docs: update CHANGELOG 2022-12-22 19:33:13 +01:00
Davide Bianchi
6e38c8b9ea Merge pull request #93 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.111.0 2022-12-22 19:26:41 +01:00
Davide Bianchi
40ea80b890 Merge pull request #94 from davidebianchi/support-fiber 2022-12-22 19:26:30 +01:00
Davide Bianchi
1daad04aab feat: change GenerateAndExposeSwagger fn name 2022-12-22 19:23:37 +01:00
Davide Bianchi
77e080c587 docs: update CHANGELOG 2022-12-22 19:15:33 +01:00
Davide Bianchi
00d9267cf8 feat: improve README 2022-12-22 19:11:37 +01:00
Davide Bianchi
efab680870 docs: update CHANGELOG 2022-12-22 18:43:13 +01:00
Davide Bianchi
fa4fd37f17 feat: add first class support to echo router 2022-12-22 18:42:41 +01:00
Davide Bianchi
74baec392e feat: move gorilla integration under gorilla folder 2022-12-22 18:27:57 +01:00
Davide Bianchi
a48fb550df feat: drop support golang below v1.17 2022-12-22 15:37:14 +01:00
Davide Bianchi
76d2e514e1 feat: add strong types on Route 2022-12-22 15:35:56 +01:00
Davide Bianchi
aeb5680612 feat: add fiber support 2022-12-22 12:44:55 +01:00
Davide Bianchi
10a5f64f5c feat: change apirouter implementation to support multiple type of handler 2022-12-22 11:29:13 +01:00
Davide Bianchi
fca6b6910d feat: move gorilla under support 2022-12-22 10:03:20 +01:00
Davide Bianchi
da751837df upgrade to go 19 2022-12-22 09:54:37 +01:00
dependabot[bot]
cbe3488c8d chore(deps): bump github.com/getkin/kin-openapi from 0.108.0 to 0.111.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.108.0 to 0.111.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.108.0...v0.111.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-19 03:03:15 +00:00
Davide Bianchi
315cd103a7 Merge pull request #88 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.108.0 2022-11-17 09:35:44 +01:00
dependabot[bot]
3a598c0726 chore(deps): bump github.com/getkin/kin-openapi from 0.107.0 to 0.108.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.107.0 to 0.108.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.107.0...v0.108.0)

---
updated-dependencies:
- dependency-name: github.com/getkin/kin-openapi
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-10 03:05:07 +00:00
49 changed files with 1679 additions and 461 deletions

View File

@@ -9,10 +9,10 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
go_version: [1.16, 1.17, 1.18, 1.19]
go_version: [1.18, 1.19]
os: [ubuntu-latest]
include:
- go_version: 1.17
- go_version: 1.19
os: macos-latest
steps:
- uses: actions/checkout@v1

View File

@@ -7,6 +7,50 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## 0.9.0 - 17-04-2023
### Added
- add new fields to Definition:
- Security
- Tags
- Summary
- Description
- Deprecated
- Extensions
### Updated
- update kin-openapi to 0.114.0: this change removes components from exposed oas (if not manually set). In this update of kin-openapi, there is a breaking change with the T struct, which now accepts component as pointer.
## 0.8.0 - 23-12-2022
### BREAKING CHANGES
- add `TransformPathToOasPath(path string) string` method to apirouter.Router interface to handle different types of paths parameters. If you use one of the supported routers, you should do nothing;
## 0.7.0 - 22-12-2022
This is a big major release. The main achievement is to increase the usability of this library to all the routers.
Below are listed the breaking changes you should care when update the version.
### BREAKING CHANGES
- `apirouter.NewGorillaMuxRouter` is now `gorilla.NewRouter` (exposed by package `github.com/davidebianchi/gswagger/support/gorilla`).
- removed `apirouter.HandlerFunc`. Now it is exposed by `gorilla.HandlerFunc`
- changed `apirouter.Router` interface:
- now it accept a generics `HandlerFunc` to define the handler function
- add method `SwaggerHandler(contentType string, json []byte) HandlerFunc`
- `NewRouter` function now accept `HandlerFunc` as generics
- drop support to golang <= 1.17
- `GenerateAndExposeSwagger` renamed to `GenerateAndExposeOpenapi`
### Feature
- support to different types of routers
- add [fiber](https://github.com/gofiber/fiber) support
- add [echo](https://echo.labstack.com/) support
## 0.6.1 - 17-11-2022
### Changed

View File

@@ -11,11 +11,13 @@
Generate an openapi spec dynamically based on the types used to handle request and response.
It works with any router which support handler net/http HandlerFunc compatible.
It works with any router, it is simple to add support to your router implementing the [apirouter](apirouter/router.go) interface.
The routers supported out of the box are:
- [gorilla-mux](https://github.com/gorilla/mux)
- [fiber](https://github.com/gofiber/fiber)
- [echo](https://echo.labstack.com/)
This lib uses [kin-openapi] to automatically generate and serve a swagger file.
@@ -25,15 +27,13 @@ It is always possible to add a totally custom swagger schema using [kin-openapi]
## Usage
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()
muxRouter := mux.NewRouter()
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), swagger.Options{
router, _ := swagger.NewRouter(gorilla.NewRouter(muxRouter), swagger.Options{
Context: context,
Openapi: &openapi3.T{
Info: &openapi3.Info{
@@ -54,7 +54,6 @@ type User struct {
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"`
}
@@ -99,39 +98,32 @@ operation := swagger.NewOperation()
operation.AddRequestBody(requestBody)
router.AddRawRoute(http.MethodPost, "/cars", okHandler, operation)
router.GenerateAndExposeOpenapi()
```
This configuration will output the schema shown [here](testdata/users_employees.json).
This configuration will output the schema shown [here](./support/gorilla/testdata/examples-users.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}`.
The path params, if not set in schema, are auto generated from the path.
The format of the path parameters depends on the router library you are using, as explained below.
For example, with this use case:
### Gorilla Mux
```golang
okHandler := func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
Gorilla Mux supports the path parameters as `{someParam}`, for example as in `/users/{userId}`.
_, 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)
```
Here is the [example test](./support/gorilla/examples_test.go).
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).
The generated OAS for this test case is visible [here](./support/gorilla/testdata/examples-users.json).
### Fiber
Fiber supports the path parameters as `:someParam`, for example as in `/users/:userId`.
Here is the [example test](./support/fiber/integration_test.go)
## SubRouter
@@ -140,7 +132,7 @@ It is possible to add a prefix to all the routes created under the specific rout
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).
To see the SubRouter example, please see the integration test of one of the supported routers.
### FAQ

View File

@@ -1,17 +0,0 @@
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,
}
}

View File

@@ -1,12 +1,7 @@
package apirouter
import "net/http"
// Handler is the http type handler
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
type Router interface {
type Router[HandlerFunc any, Route any] interface {
AddRoute(method string, path string, handler HandlerFunc) Route
SwaggerHandler(contentType string, blob []byte) HandlerFunc
TransformPathToOasPath(path string) string
}
type Route interface{}

View File

@@ -0,0 +1,15 @@
package apirouter
import (
"strings"
)
func TransformPathParamsWithColon(path string) string {
pathParams := strings.Split(path, "/")
for i, param := range pathParams {
if strings.HasPrefix(param, ":") {
pathParams[i] = strings.Replace(param, ":", "{", 1) + "}"
}
}
return strings.Join(pathParams, "/")
}

View File

@@ -0,0 +1,59 @@
package apirouter
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestTransformPathParamsWithColon(t *testing.T) {
testCases := []struct {
name string
path string
expectedPath string
}{
{
name: "only /",
path: "/",
expectedPath: "/",
},
{
name: "without params",
path: "/foo",
expectedPath: "/foo",
},
{
name: "without params ending with /",
path: "/foo/",
expectedPath: "/foo/",
},
{
name: "with params",
path: "/foo/:par1",
expectedPath: "/foo/{par1}",
},
{
name: "with params ending with /",
path: "/foo/:par1/",
expectedPath: "/foo/{par1}/",
},
{
name: "with multiple params",
path: "/:par1/:par2/:par3",
expectedPath: "/{par1}/{par2}/{par3}",
},
{
name: "with multiple params ending with /",
path: "/:par1/:par2/:par3/",
expectedPath: "/{par1}/{par2}/{par3}/",
},
}
for _, test := range testCases {
t.Run(test.name, func(t *testing.T) {
actual := TransformPathParamsWithColon(test.path)
require.Equal(t, test.expectedPath, actual)
})
}
}

36
go.mod
View File

@@ -1,35 +1,49 @@
module github.com/davidebianchi/gswagger
go 1.17
go 1.19
require (
github.com/getkin/kin-openapi v0.107.0
github.com/getkin/kin-openapi v0.115.0
github.com/ghodss/yaml v1.0.0
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gorilla/mux v1.8.0
github.com/iancoleman/orderedmap v0.2.0 // indirect
github.com/labstack/echo/v4 v4.9.1
github.com/labstack/echo/v4 v4.10.2
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mia-platform/jsonschema v0.1.0
github.com/stretchr/testify v1.8.1
github.com/stretchr/testify v1.8.2
)
require github.com/gofiber/fiber/v2 v2.44.0
require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.16.3 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/perimeterx/marshmallow v1.1.4 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/tinylib/msgp v1.1.8 // 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
github.com/valyala/fasthttp v1.45.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.8.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

117
go.sum
View File

@@ -1,9 +1,11 @@
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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.107.0 h1:bxhL6QArW7BXQj8NjXfIJQy680NsMKd25nwhvpCXchg=
github.com/getkin/kin-openapi v0.107.0/go.mod h1:9Dhr+FasATJZjS4iOLvB0hkaxgYdulrNYm2e9epLWOo=
github.com/getkin/kin-openapi v0.115.0 h1:c8WHRLVY3G8m9jQTy0/DnIuljgRwTCB5twZytQS4JyU=
github.com/getkin/kin-openapi v0.115.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
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=
@@ -11,7 +13,12 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
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/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
github.com/gofiber/fiber/v2 v2.44.0 h1:Z90bEvPcJM5GFJnu1py0E1ojoerkyew3iiNJ78MQCM8=
github.com/gofiber/fiber/v2 v2.44.0/go.mod h1:VTMtb/au8g01iqvHyaCzftuM/xmZgKOZCtFzz6CdV9w=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
@@ -22,13 +29,15 @@ 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/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY=
github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
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.1 h1:GliPYSpzGKlyOhqIbG8nmHBo3i1saKWFOgh41AN3b+Y=
github.com/labstack/echo/v4 v4.9.1/go.mod h1:Pop5HLc+xoc4qhTZ1ip6C0RtP7Z+4VzRLWZZFKqbbjo=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@@ -37,59 +46,117 @@ github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJ
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-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mia-platform/jsonschema v0.1.0 h1:tjQf7TaYROsAqk7SXTL+44TrfKk3bSEvhRGPS51IA5Y=
github.com/mia-platform/jsonschema v0.1.0/go.mod h1:r2DJjPA/+6S+WPnXZt1xONMvO2b4hlhfXfUYV0po/Dk=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
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/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0=
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/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94 h1:rmMl4fXJhKMNWl+K+r/fq4FbbKI+Ia2m9hYBLm2h4G4=
github.com/savsgio/dictpool v0.0.0-20221023140959-7bf2e61cea94/go.mod h1:90zrgN3D/WJsDd1iXHT96alCoN2KJo6/4x1DZC3wZs8=
github.com/savsgio/gotils v0.0.0-20220530130905-52f3993e8d6d/go.mod h1:Gy+0tqhJvgGlqnTF8CVGP0AaGRjwBtXs/a5PA0Y3+A4=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
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/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
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/fasthttp v1.45.0 h1:zPkkzpIn8tdHZUrVa6PzYd0i5verqiPSkgTd3bSUcpA=
github.com/valyala/fasthttp v1.45.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
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=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
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/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/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/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
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/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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=

View File

@@ -1,253 +0,0 @@
package swagger_test
import (
"context"
"io"
"net/http"
"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"
)
const (
swaggerOpenapiTitle = "test swagger title"
swaggerOpenapiVersion = "test swagger version"
)
func TestIntegration(t *testing.T) {
t.Run("router works correctly", func(t *testing.T) {
muxRouter, _ := setupSwagger(t)
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("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("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 {
t.Helper()
body, err := io.ReadAll(requestBody)
require.NoError(t, err)
return string(body)
}
func setupSwagger(t *testing.T) (*mux.Router, *swagger.Router) {
t.Helper()
context := context.Background()
muxRouter := mux.NewRouter()
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), 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", okHandler, operation)
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
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)))
}

32
main.go
View File

@@ -30,8 +30,8 @@ const (
// Router handle the api router and the swagger schema.
// api router supported out of the box are:
// - gorilla mux
type Router struct {
router apirouter.Router
type Router[HandlerFunc, Route any] struct {
router apirouter.Router[HandlerFunc, Route]
swaggerSchema *openapi3.T
context context.Context
jsonDocumentationPath string
@@ -52,8 +52,8 @@ type Options struct {
}
// NewRouter generate new router with swagger. Default to OpenAPI 3.0.0
func NewRouter(router apirouter.Router, options Options) (*Router, error) {
swagger, err := generateNewValidSwagger(options.Openapi)
func NewRouter[HandlerFunc, Route any](router apirouter.Router[HandlerFunc, Route], options Options) (*Router[HandlerFunc, Route], error) {
swagger, err := generateNewValidOpenapi(options.Openapi)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrValidatingSwagger, err)
}
@@ -79,7 +79,7 @@ func NewRouter(router apirouter.Router, options Options) (*Router, error) {
jsonDocumentationPath = options.JSONDocumentationPath
}
return &Router{
return &Router[HandlerFunc, Route]{
router: router,
swaggerSchema: swagger,
context: ctx,
@@ -93,8 +93,8 @@ type SubRouterOptions struct {
PathPrefix string
}
func (r Router) SubRouter(router apirouter.Router, opts SubRouterOptions) (*Router, error) {
return &Router{
func (r Router[HandlerFunc, Route]) SubRouter(router apirouter.Router[HandlerFunc, Route], opts SubRouterOptions) (*Router[HandlerFunc, Route], error) {
return &Router[HandlerFunc, Route]{
router: router,
swaggerSchema: r.swaggerSchema,
context: r.context,
@@ -104,7 +104,7 @@ func (r Router) SubRouter(router apirouter.Router, opts SubRouterOptions) (*Rout
}, nil
}
func generateNewValidSwagger(swagger *openapi3.T) (*openapi3.T, error) {
func generateNewValidOpenapi(swagger *openapi3.T) (*openapi3.T, error) {
if swagger == nil {
return nil, fmt.Errorf("swagger is required")
}
@@ -128,9 +128,9 @@ func generateNewValidSwagger(swagger *openapi3.T) (*openapi3.T, error) {
return swagger, nil
}
// GenerateAndExposeSwagger creates a /documentation/json route on router and
// GenerateAndExposeOpenapi creates a /documentation/json route on router and
// expose the generated swagger
func (r Router) GenerateAndExposeSwagger() error {
func (r Router[_, _]) GenerateAndExposeOpenapi() error {
if err := r.swaggerSchema.Validate(r.context); err != nil {
return fmt.Errorf("%w: %s", ErrValidatingSwagger, err)
}
@@ -139,21 +139,13 @@ func (r Router) GenerateAndExposeSwagger() error {
if err != nil {
return fmt.Errorf("%w json marshal: %s", ErrGenerateSwagger, err)
}
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)
})
r.router.AddRoute(http.MethodGet, r.jsonDocumentationPath, r.router.SwaggerHandler("application/json", jsonSwagger))
yamlSwagger, err := yaml.JSONToYAML(jsonSwagger)
if err != nil {
return fmt.Errorf("%w yaml marshal: %s", ErrGenerateSwagger, err)
}
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)
})
r.router.AddRoute(http.MethodGet, r.yamlDocumentationPath, r.router.SwaggerHandler("text/plain", yamlSwagger))
return nil
}

View File

@@ -10,7 +10,7 @@ import (
"strings"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/davidebianchi/gswagger/support/gorilla"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
@@ -18,7 +18,7 @@ import (
func TestNewRouter(t *testing.T) {
muxRouter := mux.NewRouter()
mAPIRouter := apirouter.NewGorillaMuxRouter(muxRouter)
mAPIRouter := gorilla.NewRouter(muxRouter)
info := &openapi3.Info{
Title: "my title",
@@ -42,7 +42,7 @@ func TestNewRouter(t *testing.T) {
})
require.NoError(t, err)
require.Equal(t, &Router{
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
context: context.Background(),
router: mAPIRouter,
swaggerSchema: openapi,
@@ -60,7 +60,7 @@ func TestNewRouter(t *testing.T) {
})
require.NoError(t, err)
require.Equal(t, &Router{
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
context: ctx,
router: mAPIRouter,
swaggerSchema: openapi,
@@ -80,7 +80,7 @@ func TestNewRouter(t *testing.T) {
})
require.NoError(t, err)
require.Equal(t, &Router{
require.Equal(t, &Router[gorilla.HandlerFunc, gorilla.Route]{
context: ctx,
router: mAPIRouter,
swaggerSchema: openapi,
@@ -122,7 +122,7 @@ func TestGenerateValidSwagger(t *testing.T) {
t.Run("not ok - empty swagger info", func(t *testing.T) {
swagger := &openapi3.T{}
swagger, err := generateNewValidSwagger(swagger)
swagger, err := generateNewValidOpenapi(swagger)
require.Nil(t, swagger)
require.EqualError(t, err, "swagger info is required")
})
@@ -132,7 +132,7 @@ func TestGenerateValidSwagger(t *testing.T) {
Info: &openapi3.Info{},
}
swagger, err := generateNewValidSwagger(swagger)
swagger, err := generateNewValidOpenapi(swagger)
require.Nil(t, swagger)
require.EqualError(t, err, "swagger info title is required")
})
@@ -144,7 +144,7 @@ func TestGenerateValidSwagger(t *testing.T) {
},
}
swagger, err := generateNewValidSwagger(swagger)
swagger, err := generateNewValidOpenapi(swagger)
require.Nil(t, swagger)
require.EqualError(t, err, "swagger info version is required")
})
@@ -154,13 +154,13 @@ func TestGenerateValidSwagger(t *testing.T) {
Info: &openapi3.Info{},
}
swagger, err := generateNewValidSwagger(swagger)
swagger, err := generateNewValidOpenapi(swagger)
require.Nil(t, swagger)
require.EqualError(t, err, "swagger info title is required")
})
t.Run("not ok - swagger is required", func(t *testing.T) {
swagger, err := generateNewValidSwagger(nil)
swagger, err := generateNewValidOpenapi(nil)
require.Nil(t, swagger)
require.EqualError(t, err, "swagger is required")
})
@@ -174,7 +174,7 @@ func TestGenerateValidSwagger(t *testing.T) {
Info: info,
}
swagger, err := generateNewValidSwagger(swagger)
swagger, err := generateNewValidOpenapi(swagger)
require.NoError(t, err)
require.Equal(t, &openapi3.T{
OpenAPI: defaultOpenapiVersion,
@@ -187,13 +187,13 @@ 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(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "title",
Version: "version",
},
Components: openapi3.Components{
Components: &openapi3.Components{
Schemas: map[string]*openapi3.SchemaRef{
"&%": {},
},
@@ -202,7 +202,7 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.Error(t, err)
require.True(t, strings.HasPrefix(err.Error(), fmt.Sprintf("%s:", ErrValidatingSwagger)))
})
@@ -213,12 +213,12 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: swagger,
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -240,13 +240,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: swagger,
JSONDocumentationPath: "/custom/path",
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -268,12 +268,12 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: swagger,
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -295,13 +295,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: swagger,
YAMLDocumentationPath: "/custom/path",
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -320,7 +320,7 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("ok - subrouter", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
@@ -336,8 +336,8 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
w.Write([]byte("ok"))
}, Definitions{})
mSubRouter := mRouter.PathPrefix("/prefix").Subrouter()
subrouter, err := router.SubRouter(apirouter.NewGorillaMuxRouter(mSubRouter), SubRouterOptions{
mSubRouter := mRouter.NewRoute().Subrouter()
subrouter, err := router.SubRouter(gorilla.NewRouter(mSubRouter), SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
@@ -356,7 +356,7 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
require.NoError(t, err)
})
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -370,12 +370,36 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
actual, err := os.ReadFile("testdata/subrouter.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
t.Run("test request /prefix", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/prefix", nil)
mRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
})
t.Run("test request /prefix/taz", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/prefix/taz", nil)
mRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
})
t.Run("test request /foo", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/foo", nil)
mRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
})
})
t.Run("ok - new router with path prefix", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
router, err := NewRouter(gorilla.NewRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
@@ -392,7 +416,7 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
w.Write([]byte("ok"))
}, Definitions{})
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
w := httptest.NewRecorder()
@@ -405,7 +429,7 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
body := readBody(t, w.Result().Body)
actual, err := os.ReadFile("testdata/router_with_prefix.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
require.JSONEq(t, string(actual), body, body)
})
}

View File

@@ -37,3 +37,12 @@ func (o *Operation) AddResponse(status int, response *openapi3.Response) {
}
o.Operation.AddResponse(status, response)
}
func (o *Operation) addSecurityRequirements(securityRequirements SecurityRequirements) {
if securityRequirements != nil && o.Security == nil {
o.Security = openapi3.NewSecurityRequirements()
}
for _, securityRequirement := range securityRequirements {
o.Security.With(openapi3.SecurityRequirement(securityRequirement))
}
}

View File

@@ -27,7 +27,7 @@ func TestNewOperation(t *testing.T) {
operation.Responses = openapi3.NewResponses()
return operation
},
expectedJSON: `{"components":{},"info":{"title":"test swagger title","version":"test swagger version"},"openapi":"3.0.0","paths":{"/":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"bar":{"maximum":15,"minimum":5,"type":"integer"},"foo":{"type":"string"}},"type":"object"}}}},"responses":{"default":{"description":""}}}}}}`,
expectedJSON: `{"info":{"title":"test swagger title","version":"test swagger version"},"openapi":"3.0.0","paths":{"/":{"post":{"requestBody":{"content":{"application/json":{"schema":{"properties":{"bar":{"maximum":15,"minimum":5,"type":"integer"},"foo":{"type":"string"}},"type":"object"}}}},"responses":{"default":{"description":""}}}}}}`,
},
{
name: "add response",
@@ -36,7 +36,7 @@ func TestNewOperation(t *testing.T) {
operation.AddResponse(200, response)
return operation
},
expectedJSON: `{"components":{},"info":{"title":"test swagger title","version":"test swagger version"},"openapi":"3.0.0","paths":{"/":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"bar":{"maximum":15,"minimum":5,"type":"integer"},"foo":{"type":"string"}},"type":"object"}}},"description":""}}}}}}`,
expectedJSON: `{"info":{"title":"test swagger title","version":"test swagger version"},"openapi":"3.0.0","paths":{"/":{"post":{"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"bar":{"maximum":15,"minimum":5,"type":"integer"},"foo":{"type":"string"}},"type":"object"}}},"description":""}}}}}}`,
},
}

View File

@@ -7,7 +7,6 @@ import (
"sort"
"strings"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/mia-platform/jsonschema"
)
@@ -25,12 +24,12 @@ 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, routePath string, handler apirouter.HandlerFunc, operation Operation) (interface{}, error) {
func (r Router[HandlerFunc, Route]) AddRawRoute(method string, routePath string, handler HandlerFunc, operation Operation) (Route, error) {
op := operation.Operation
if op != nil {
err := operation.Validate(r.context)
if err != nil {
return nil, err
return getZero[Route](), err
}
} else {
op = openapi3.NewOperation()
@@ -39,7 +38,8 @@ func (r Router) AddRawRoute(method string, routePath string, handler apirouter.H
}
}
pathWithPrefix := path.Join(r.pathPrefix, routePath)
r.swaggerSchema.AddOperation(pathWithPrefix, method, op)
oasPath := r.router.TransformPathToOasPath(pathWithPrefix)
r.swaggerSchema.AddOperation(oasPath, method, op)
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
return r.router.AddRoute(method, pathWithPrefix, handler), nil
@@ -71,15 +71,42 @@ type ContentValue struct {
Description string
}
type SecurityRequirements []SecurityRequirement
type SecurityRequirement map[string][]string
// Definitions of the route.
// To see how to use, refer to https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md
type Definitions struct {
// Specification extensions https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specification-extensions
Extensions map[string]interface{}
// Optional field for documentation
Tags []string
Summary string
Description string
Deprecated bool
// PathParams contains the path parameters. If empty is autocompleted from the path
PathParams ParameterValue
Querystring ParameterValue
Headers ParameterValue
Cookies ParameterValue
RequestBody *ContentValue
Responses map[int]ContentValue
Security SecurityRequirements
}
func newOperationFromDefinition(schema Definitions) Operation {
operation := NewOperation()
operation.Responses = make(openapi3.Responses)
operation.Tags = schema.Tags
operation.Extensions = schema.Extensions
operation.addSecurityRequirements(schema.Security)
operation.Description = schema.Description
operation.Summary = schema.Summary
operation.Deprecated = schema.Deprecated
return operation
}
const (
@@ -89,46 +116,45 @@ const (
cookieParamType = "cookie"
)
// AddRoute add a route with json schema inferted by passed schema.
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
// AddRoute add a route with json schema inferred by passed schema.
func (r Router[HandlerFunc, Route]) AddRoute(method string, path string, handler HandlerFunc, schema Definitions) (Route, error) {
operation := newOperationFromDefinition(schema)
err := r.resolveRequestBodySchema(schema.RequestBody, operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrRequestBody, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrRequestBody, err)
}
err = r.resolveResponsesSchema(schema.Responses, operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrResponses, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrResponses, err)
}
err = r.resolveParameterSchema(pathParamsType, getPathParamsAutofilled(schema, path), operation)
oasPath := r.router.TransformPathToOasPath(path)
err = r.resolveParameterSchema(pathParamsType, getPathParamsAutoComplete(schema, oasPath), operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrPathParams, err)
}
err = r.resolveParameterSchema(queryParamType, schema.Querystring, operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrPathParams, err)
}
err = r.resolveParameterSchema(headerParamType, schema.Headers, operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrPathParams, err)
}
err = r.resolveParameterSchema(cookieParamType, schema.Cookies, operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
return getZero[Route](), fmt.Errorf("%w: %s", ErrPathParams, err)
}
return r.AddRawRoute(method, path, handler, operation)
}
func (r Router) getSchemaFromInterface(v interface{}, allowAdditionalProperties bool) (*openapi3.Schema, error) {
func (r Router[_, _]) getSchemaFromInterface(v interface{}, allowAdditionalProperties bool) (*openapi3.Schema, error) {
if v == nil {
return &openapi3.Schema{}, nil
}
@@ -159,7 +185,7 @@ func (r Router) getSchemaFromInterface(v interface{}, allowAdditionalProperties
return schema, nil
}
func (r Router) resolveRequestBodySchema(bodySchema *ContentValue, operation Operation) error {
func (r Router[_, _]) resolveRequestBodySchema(bodySchema *ContentValue, operation Operation) error {
if bodySchema == nil {
return nil
}
@@ -178,7 +204,7 @@ func (r Router) resolveRequestBodySchema(bodySchema *ContentValue, operation Ope
return nil
}
func (r Router) resolveResponsesSchema(responses map[int]ContentValue, operation Operation) error {
func (r Router[_, _]) resolveResponsesSchema(responses map[int]ContentValue, operation Operation) error {
if responses == nil {
operation.Responses = openapi3.NewResponses()
}
@@ -197,7 +223,7 @@ func (r Router) resolveResponsesSchema(responses map[int]ContentValue, operation
return nil
}
func (r Router) resolveParameterSchema(paramType string, paramConfig ParameterValue, operation Operation) error {
func (r Router[_, _]) resolveParameterSchema(paramType string, paramConfig ParameterValue, operation Operation) error {
var keys = make([]string, 0, len(paramConfig))
for k := range paramConfig {
keys = append(keys, k)
@@ -248,7 +274,7 @@ func (r Router) resolveParameterSchema(paramType string, paramConfig ParameterVa
return nil
}
func (r Router) addContentToOASSchema(content Content) (openapi3.Content, error) {
func (r Router[_, _]) addContentToOASSchema(content Content) (openapi3.Content, error) {
oasContent := openapi3.NewContent()
for k, v := range content {
var err error
@@ -261,7 +287,7 @@ func (r Router) addContentToOASSchema(content Content) (openapi3.Content, error)
return oasContent, nil
}
func getPathParamsAutofilled(schema Definitions, path string) ParameterValue {
func getPathParamsAutoComplete(schema Definitions, path string) ParameterValue {
if schema.PathParams == nil {
pathParams := strings.Split(path, "/")
for _, param := range pathParams {
@@ -279,3 +305,8 @@ func getPathParamsAutofilled(schema Definitions, path string) ParameterValue {
}
return schema.PathParams
}
func getZero[T any]() T {
var result T
return result
}

View File

@@ -8,7 +8,7 @@ import (
"os"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/davidebianchi/gswagger/support/gorilla"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
@@ -17,8 +17,9 @@ import (
const jsonType = "application/json"
const formDataType = "multipart/form-data"
func TestAddRoutes(t *testing.T) {
type TestRouter = Router[gorilla.HandlerFunc, gorilla.Route]
func TestAddRoutes(t *testing.T) {
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"`
@@ -56,19 +57,19 @@ func TestAddRoutes(t *testing.T) {
tests := []struct {
name string
routes func(t *testing.T, router *Router)
routes func(t *testing.T, router *TestRouter)
fixturesPath string
testPath string
testMethod string
}{
{
name: "no routes",
routes: func(t *testing.T, router *Router) {},
routes: func(t *testing.T, router *TestRouter) {},
fixturesPath: "testdata/empty.json",
},
{
name: "empty route schema",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodPost, "/", okHandler, Definitions{})
require.NoError(t, err)
},
@@ -78,7 +79,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "multiple real routes",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodPost, "/users", okHandler, Definitions{
RequestBody: &ContentValue{
Content: Content{
@@ -128,7 +129,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "multipart request body",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodPost, "/files", okHandler, Definitions{
RequestBody: &ContentValue{
Content: Content{
@@ -157,7 +158,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema with params",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
var number = 0
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
PathParams: ParameterValue{
@@ -186,7 +187,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema without params autofilled",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
Querystring: ParameterValue{
"query": {
@@ -204,7 +205,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema with querystring",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/projects", okHandler, Definitions{
Querystring: ParameterValue{
"projectId": {
@@ -220,7 +221,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema with headers",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/projects", okHandler, Definitions{
Headers: ParameterValue{
"foo": {
@@ -239,7 +240,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema with cookies",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/projects", okHandler, Definitions{
Cookies: ParameterValue{
"debug": {
@@ -258,7 +259,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema defined without value",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodPost, "/{id}", okHandler, Definitions{
RequestBody: &ContentValue{
Description: "request body without schema",
@@ -287,7 +288,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "allOf schema",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
schema := openapi3.NewAllOfSchema()
schema.AllOf = []*openapi3.SchemaRef{
{
@@ -332,7 +333,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "anyOf schema",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
schema := openapi3.NewAnyOfSchema()
schema.AnyOf = []*openapi3.SchemaRef{
{
@@ -376,7 +377,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "oneOf support on properties",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodPost, "/user-profile", okHandler, Definitions{
RequestBody: &ContentValue{
Content: Content{
@@ -424,7 +425,7 @@ func TestAddRoutes(t *testing.T) {
},
{
name: "schema with tags",
routes: func(t *testing.T, router *Router) {
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Tags: []string{"Tag1", "Tag2"},
})
@@ -433,6 +434,66 @@ func TestAddRoutes(t *testing.T) {
testPath: "/users",
fixturesPath: "testdata/tags.json",
},
{
name: "schema with security",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Security: SecurityRequirements{
SecurityRequirement{
"api_key": []string{},
"auth": []string{
"resource.write",
},
},
},
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/security.json",
},
{
name: "schema with extension",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Extensions: map[string]interface{}{
"x-extension-field": map[string]string{
"foo": "bar",
},
},
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/extension.json",
},
{
name: "invalid extension - not starts with x-",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/", okHandler, Definitions{
Extensions: map[string]interface{}{
"extension-field": map[string]string{
"foo": "bar",
},
},
})
require.EqualError(t, err, "extra sibling fields: [extension-field]")
},
fixturesPath: "testdata/empty.json",
},
{
name: "schema with summary, description, deprecated and operationID",
routes: func(t *testing.T, router *TestRouter) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Summary: "small description",
Description: "this is the long route description",
Deprecated: true,
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/users-deprecated-with-description.json",
},
}
for _, test := range tests {
@@ -440,7 +501,7 @@ func TestAddRoutes(t *testing.T) {
context := context.Background()
r := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(r), Options{
router, err := NewRouter(gorilla.NewRouter(r), Options{
Context: context,
Openapi: getBaseSwagger(t),
})
@@ -450,7 +511,7 @@ func TestAddRoutes(t *testing.T) {
// Add routes to test
test.routes(t, router)
err = router.GenerateAndExposeSwagger()
err = router.GenerateAndExposeOpenapi()
require.NoError(t, err)
if test.testPath != "" {
@@ -630,7 +691,7 @@ func TestResolveRequestBodySchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
router, err := NewRouter(gorilla.NewRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)
@@ -854,7 +915,7 @@ func TestResolveResponsesSchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
router, err := NewRouter(gorilla.NewRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)
@@ -1024,7 +1085,7 @@ func TestResolveParametersSchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
router, err := NewRouter(gorilla.NewRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)

36
support/echo/echo.go Normal file
View File

@@ -0,0 +1,36 @@
package echo
import (
"github.com/davidebianchi/gswagger/apirouter"
"net/http"
"github.com/labstack/echo/v4"
)
type Route = *echo.Route
type echoRouter struct {
router *echo.Echo
}
func (r echoRouter) AddRoute(method string, path string, handler echo.HandlerFunc) Route {
return r.router.Add(method, path, handler)
}
func (r echoRouter) SwaggerHandler(contentType string, blob []byte) echo.HandlerFunc {
return func(c echo.Context) error {
c.Response().Header().Add("Content-Type", contentType)
return c.JSONBlob(http.StatusOK, blob)
}
}
func (r echoRouter) TransformPathToOasPath(path string) string {
return apirouter.TransformPathParamsWithColon(path)
}
func NewRouter(router *echo.Echo) apirouter.Router[echo.HandlerFunc, Route] {
return echoRouter{
router: router,
}
}

65
support/echo/echo_test.go Normal file
View File

@@ -0,0 +1,65 @@
package echo
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/require"
)
func TestGorillaMuxRouter(t *testing.T) {
echoRouter := echo.New()
ar := NewRouter(echoRouter)
t.Run("create a new api router", func(t *testing.T) {
require.Implements(t, (*apirouter.Router[echo.HandlerFunc, Route])(nil), ar)
})
t.Run("add new route", func(t *testing.T) {
route := ar.AddRoute(http.MethodGet, "/foo", func(c echo.Context) error {
return c.String(http.StatusOK, "")
})
require.IsType(t, route, &echo.Route{})
t.Run("router exposes correctly api", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/foo", nil)
echoRouter.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)
echoRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusMethodNotAllowed, w.Result().StatusCode)
})
})
t.Run("create openapi handler", func(t *testing.T) {
handlerFunc := ar.SwaggerHandler("text/html", []byte("some data"))
echoRouter.GET("/oas", handlerFunc)
t.Run("responds correctly to the API", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/oas", nil)
echoRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
require.Equal(t, "text/html", w.Result().Header.Get("Content-Type"))
body, err := io.ReadAll(w.Result().Body)
require.NoError(t, err)
require.Equal(t, "some data", string(body))
})
})
}

View File

@@ -0,0 +1,170 @@
package echo_test
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
oasEcho "github.com/davidebianchi/gswagger/support/echo"
swagger "github.com/davidebianchi/gswagger"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/require"
)
const (
swaggerOpenapiTitle = "test swagger title"
swaggerOpenapiVersion = "test swagger version"
)
type echoSwaggerRouter = swagger.Router[echo.HandlerFunc, *echo.Route]
func TestEchoIntegration(t *testing.T) {
t.Run("router works correctly - echo", func(t *testing.T) {
echoRouter, oasRouter := setupEchoSwagger(t)
err := oasRouter.GenerateAndExposeOpenapi()
require.NoError(t, err)
t.Run("/hello", func(t *testing.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("/hello/:value", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPost, "/hello/something", 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.JSONEq(t, readFile(t, "../testdata/integration.json"), body)
})
})
t.Run("works correctly with subrouter - handles path prefix - echo", func(t *testing.T) {
eRouter, oasRouter := setupEchoSwagger(t)
subRouter, err := oasRouter.SubRouter(oasEcho.NewRouter(eRouter), swagger.SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
require.NoError(t, err)
err = oasRouter.GenerateAndExposeOpenapi()
require.NoError(t, err)
t.Run("correctly call /hello", func(t *testing.T) {
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.JSONEq(t, readFile(t, "../testdata/intergation-subrouter.json"), body, body)
})
})
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {
t.Helper()
body, err := io.ReadAll(requestBody)
require.NoError(t, err)
return string(body)
}
func setupEchoSwagger(t *testing.T) (*echo.Echo, *echoSwaggerRouter) {
t.Helper()
context := context.Background()
e := echo.New()
router, err := swagger.NewRouter(oasEcho.NewRouter(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", okHandler, operation)
require.NoError(t, err)
_, err = router.AddRoute(http.MethodPost, "/hello/:value", okHandler, swagger.Definitions{})
require.NoError(t, err)
return e, router
}
func okHandler(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
func readFile(t *testing.T, path string) string {
t.Helper()
fileContent, err := os.ReadFile(path)
require.NoError(t, err)
return string(fileContent)
}

34
support/fiber/fiber.go Normal file
View File

@@ -0,0 +1,34 @@
package fiber
import (
"github.com/davidebianchi/gswagger/apirouter"
"github.com/gofiber/fiber/v2"
)
type HandlerFunc = fiber.Handler
type Route = fiber.Router
type fiberRouter struct {
router fiber.Router
}
func NewRouter(router fiber.Router) apirouter.Router[HandlerFunc, Route] {
return fiberRouter{
router: router,
}
}
func (r fiberRouter) AddRoute(method string, path string, handler HandlerFunc) Route {
return r.router.Add(method, path, handler)
}
func (r fiberRouter) SwaggerHandler(contentType string, blob []byte) HandlerFunc {
return func(c *fiber.Ctx) error {
c.Set("Content-Type", contentType)
return c.Send(blob)
}
}
func (r fiberRouter) TransformPathToOasPath(path string) string {
return apirouter.TransformPathParamsWithColon(path)
}

View File

@@ -0,0 +1,63 @@
package fiber
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/require"
)
func TestFiberRouterSupport(t *testing.T) {
fiberRouter := fiber.New()
ar := NewRouter(fiberRouter)
t.Run("create a new api router", func(t *testing.T) {
require.Implements(t, (*apirouter.Router[HandlerFunc, Route])(nil), ar)
})
t.Run("add new route", func(t *testing.T) {
route := ar.AddRoute(http.MethodGet, "/foo", func(c *fiber.Ctx) error {
return c.SendStatus(http.StatusOK)
})
require.IsType(t, route, fiber.New())
t.Run("router exposes correctly api", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/foo", nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
})
t.Run("router exposes api only to the specific method", func(t *testing.T) {
r := httptest.NewRequest(http.MethodPost, "/foo", nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
})
})
t.Run("create openapi handler", func(t *testing.T) {
handlerFunc := ar.SwaggerHandler("text/html", []byte("some data"))
fiberRouter.Get("/oas", handlerFunc)
t.Run("responds correctly to the API", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/oas", nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
require.Equal(t, "text/html", resp.Header.Get("Content-Type"))
body, err := io.ReadAll(resp.Body)
require.NoError(t, err)
require.Equal(t, "some data", string(body))
})
})
}

View File

@@ -0,0 +1,165 @@
package fiber_test
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
swagger "github.com/davidebianchi/gswagger"
oasFiber "github.com/davidebianchi/gswagger/support/fiber"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/require"
)
type SwaggerRouter = swagger.Router[oasFiber.HandlerFunc, oasFiber.Route]
const (
swaggerOpenapiTitle = "test swagger title"
swaggerOpenapiVersion = "test swagger version"
)
func TestFiberIntegration(t *testing.T) {
t.Run("router works correctly", func(t *testing.T) {
router, oasRouter := setupSwagger(t)
err := oasRouter.GenerateAndExposeOpenapi()
require.NoError(t, err)
t.Run("/hello", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
resp, err := router.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.Equal(t, "OK", body)
})
t.Run("/hello/:value", func(t *testing.T) {
r := httptest.NewRequest(http.MethodPost, "/hello/something", nil)
resp, err := router.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.Equal(t, "OK", body)
})
t.Run("and generate swagger", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
resp, err := router.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.JSONEq(t, readFile(t, "../testdata/integration.json"), body, body)
})
})
t.Run("works correctly with subrouter - handles path prefix - gorilla mux", func(t *testing.T) {
fiberRouter, oasRouter := setupSwagger(t)
subRouter, err := oasRouter.SubRouter(oasFiber.NewRouter(fiberRouter), swagger.SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
require.NoError(t, err)
err = oasRouter.GenerateAndExposeOpenapi()
require.NoError(t, err)
t.Run("correctly call /hello", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.Equal(t, "OK", body)
})
t.Run("correctly call sub router", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/prefix/foo", nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.Equal(t, "OK", body)
})
t.Run("and generate swagger", func(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
resp, err := fiberRouter.Test(r)
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
body := readBody(t, resp.Body)
require.JSONEq(t, readFile(t, "../testdata/intergation-subrouter.json"), body, body)
})
})
}
func setupSwagger(t *testing.T) (*fiber.App, *SwaggerRouter) {
t.Helper()
context := context.Background()
fiberRouter := fiber.New()
router, err := swagger.NewRouter(oasFiber.NewRouter(fiberRouter), 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", okHandler, operation)
require.NoError(t, err)
_, err = router.AddRoute(http.MethodPost, "/hello/:value", okHandler, swagger.Definitions{})
require.NoError(t, err)
return fiberRouter, router
}
func okHandler(c *fiber.Ctx) error {
c.Status(http.StatusOK)
return c.SendString("OK")
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {
t.Helper()
body, err := io.ReadAll(requestBody)
require.NoError(t, err)
return string(body)
}
func readFile(t *testing.T, path string) string {
t.Helper()
fileContent, err := os.ReadFile(path)
require.NoError(t, err)
return string(fileContent)
}

View File

@@ -0,0 +1,118 @@
package gorilla_test
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
swagger "github.com/davidebianchi/gswagger"
"github.com/davidebianchi/gswagger/support/gorilla"
"github.com/stretchr/testify/require"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
)
func TestExample(t *testing.T) {
context := context.Background()
muxRouter := mux.NewRouter()
router, _ := swagger.NewRouter(gorilla.NewRouter(muxRouter), swagger.Options{
Context: context,
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "my title",
Version: "1.0.0",
},
},
})
okHandler := func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
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 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]swagger.ContentValue{
201: {
Content: swagger.Content{
"text/html": {Value: ""},
},
},
401: {
Content: swagger.Content{
"application/json": {Value: &errorResponse{}},
},
Description: "invalid request",
},
},
})
router.AddRoute(http.MethodGet, "/users", okHandler, swagger.Definitions{
Responses: map[int]swagger.ContentValue{
200: {
Content: swagger.Content{
"application/json": {Value: &[]User{}},
},
},
},
})
carSchema := openapi3.NewObjectSchema().WithProperties(map[string]*openapi3.Schema{
"foo": openapi3.NewStringSchema(),
"bar": openapi3.NewIntegerSchema().WithMax(15).WithMin(5),
})
requestBody := openapi3.NewRequestBody().WithJSONSchema(carSchema)
operation := swagger.NewOperation()
operation.AddRequestBody(requestBody)
router.AddRawRoute(http.MethodPost, "/cars", okHandler, operation)
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, swagger.Definitions{
Querystring: swagger.ParameterValue{
"query": {
Schema: &swagger.Schema{Value: ""},
},
},
})
require.NoError(t, err)
_, err = router.AddRoute(http.MethodGet, "/cars/{carId}/drivers/{driverId}", okHandler, swagger.Definitions{})
require.NoError(t, err)
router.GenerateAndExposeOpenapi()
t.Run("correctly exposes documentation", func(t *testing.T) {
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
muxRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
require.Equal(t, "application/json", w.Result().Header.Get("Content-Type"))
body, err := io.ReadAll(w.Result().Body)
require.NoError(t, err)
expected, err := os.ReadFile("./testdata/examples-users.json")
require.NoError(t, err)
require.JSONEq(t, string(expected), string(body), "actual json data: %s", body)
})
}

View File

@@ -0,0 +1,39 @@
package gorilla
import (
"github.com/davidebianchi/gswagger/apirouter"
"net/http"
"github.com/gorilla/mux"
)
// HandlerFunc is the http type handler used by gorilla/mux
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
type Route = *mux.Route
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 (r gorillaRouter) SwaggerHandler(contentType string, blob []byte) HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", contentType)
w.WriteHeader(http.StatusOK)
w.Write(blob)
}
}
func (r gorillaRouter) TransformPathToOasPath(path string) string {
return path
}
func NewRouter(router *mux.Router) apirouter.Router[HandlerFunc, Route] {
return gorillaRouter{
router: router,
}
}

View File

@@ -1,20 +1,22 @@
package apirouter
package gorilla
import (
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
)
func TestGorillaMuxRouter(t *testing.T) {
muxRouter := mux.NewRouter()
ar := NewGorillaMuxRouter(muxRouter)
ar := NewRouter(muxRouter)
t.Run("create a new api router", func(t *testing.T) {
require.Implements(t, (*Router)(nil), ar)
require.Implements(t, (*apirouter.Router[HandlerFunc, Route])(nil), ar)
})
t.Run("add new route", func(t *testing.T) {
@@ -22,9 +24,7 @@ func TestGorillaMuxRouter(t *testing.T) {
w.WriteHeader(200)
w.Write(nil)
})
_, ok := route.(*mux.Route)
require.True(t, ok)
require.IsType(t, route, &mux.Route{})
t.Run("router exposes correctly api", func(t *testing.T) {
w := httptest.NewRecorder()
@@ -44,4 +44,23 @@ func TestGorillaMuxRouter(t *testing.T) {
require.Equal(t, http.StatusMethodNotAllowed, w.Result().StatusCode)
})
})
t.Run("create openapi handler", func(t *testing.T) {
handlerFunc := ar.SwaggerHandler("text/html", []byte("some data"))
muxRouter.HandleFunc("/oas", handlerFunc).Methods(http.MethodGet)
t.Run("responds correctly to the API", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/oas", nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
require.Equal(t, "text/html", w.Result().Header.Get("Content-Type"))
body, err := io.ReadAll(w.Result().Body)
require.NoError(t, err)
require.Equal(t, "some data", string(body))
})
})
}

View File

@@ -0,0 +1,157 @@
package gorilla_test
import (
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
swagger "github.com/davidebianchi/gswagger"
"github.com/davidebianchi/gswagger/support/gorilla"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
)
const (
swaggerOpenapiTitle = "test swagger title"
swaggerOpenapiVersion = "test swagger version"
)
type SwaggerRouter = swagger.Router[gorilla.HandlerFunc, gorilla.Route]
func TestGorillaIntegration(t *testing.T) {
t.Run("router works correctly", func(t *testing.T) {
muxRouter, oasRouter := setupSwagger(t)
err := oasRouter.GenerateAndExposeOpenapi()
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("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.JSONEq(t, readFile(t, "../testdata/integration.json"), body)
})
})
t.Run("works correctly with subrouter - handles path prefix - gorilla mux", func(t *testing.T) {
muxRouter, oasRouter := setupSwagger(t)
muxSubRouter := muxRouter.NewRoute().Subrouter()
subRouter, err := oasRouter.SubRouter(gorilla.NewRouter(muxSubRouter), swagger.SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
require.NoError(t, err)
err = oasRouter.GenerateAndExposeOpenapi()
require.NoError(t, err)
t.Run("correctly call router", func(t *testing.T) {
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.JSONEq(t, readFile(t, "../testdata/intergation-subrouter.json"), body, body)
})
})
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {
t.Helper()
body, err := io.ReadAll(requestBody)
require.NoError(t, err)
return string(body)
}
func setupSwagger(t *testing.T) (*mux.Router, *SwaggerRouter) {
t.Helper()
context := context.Background()
muxRouter := mux.NewRouter()
router, err := swagger.NewRouter(gorilla.NewRouter(muxRouter), 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", okHandler, operation)
require.NoError(t, err)
_, err = router.AddRoute(http.MethodPost, "/hello/{value}", okHandler, swagger.Definitions{})
require.NoError(t, err)
return muxRouter, router
}
func okHandler(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`OK`))
}
func readFile(t *testing.T, path string) string {
t.Helper()
fileContent, err := os.ReadFile(path)
require.NoError(t, err)
return string(fileContent)
}

View File

@@ -0,0 +1,185 @@
{
"info": {
"title": "my title",
"version": "1.0.0"
},
"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": {
"get": {
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"items": {
"additionalProperties": false,
"properties": {
"address": {
"title": "user address",
"type": "string"
},
"groups": {
"default": [
"users"
],
"items": {
"type": "string"
},
"title": "groups of the user",
"type": "array"
},
"name": {
"example": "Jane",
"title": "The user name",
"type": "string"
},
"phone": {
"title": "mobile number of user",
"type": "integer"
}
},
"required": [
"name",
"phone",
"address"
],
"type": "object"
},
"type": "array"
}
}
},
"description": ""
}
}
},
"post": {
"requestBody": {
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"address": {
"title": "user address",
"type": "string"
},
"groups": {
"default": [
"users"
],
"items": {
"type": "string"
},
"title": "groups of the user",
"type": "array"
},
"name": {
"example": "Jane",
"title": "The user name",
"type": "string"
},
"phone": {
"title": "mobile number of user",
"type": "integer"
}
},
"required": [
"name",
"phone",
"address"
],
"type": "object"
}
}
}
},
"responses": {
"201": {
"content": {
"text/html": {
"schema": {
"type": "string"
}
}
},
"description": ""
},
"401": {
"content": {
"application/json": {
"schema": {
"additionalProperties": false,
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"type": "object"
}
}
},
"description": "invalid request"
}
}
}
},
"/users/{userId}": {
"get": {
"parameters": [
{
"in": "path",
"name": "userId",
"required": true,
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
}
}
}
}
}
}

37
support/testdata/integration.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/hello": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
},
"/hello/{value}": {
"post": {
"parameters": [
{
"in": "path",
"name": "value",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
}
}
}
}
}
}

View File

@@ -0,0 +1,46 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/hello": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
},
"/hello/{value}": {
"post": {
"parameters": [
{
"in": "path",
"name": "value",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
}
}
}
},
"/prefix/foo": {
"get": {
"responses": {
"default": {
"description": ""
}
}
}
}
}
}

1
testdata/allof.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

1
testdata/anyof.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

1
testdata/empty.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

21
testdata/extension.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"responses": {
"default": {
"description": ""
}
},
"x-extension-field": {
"foo": "bar"
}
}
}
}
}

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

1
testdata/oneOf.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

1
testdata/query.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

26
testdata/security.json vendored Normal file
View File

@@ -0,0 +1,26 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"responses": {
"default": {
"description": ""
}
},
"security": [
{
"api_key": [],
"auth": [
"resource.write"
]
}
]
}
}
}
}

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

1
testdata/tags.json vendored
View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -0,0 +1,21 @@
{
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"deprecated": true,
"description": "this is the long route description",
"responses": {
"default": {
"description": ""
}
},
"summary": "small description"
}
}
}
}

View File

@@ -1,5 +1,4 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"

View File

@@ -1,4 +1,3 @@
components: {}
info:
title: test swagger title
version: test swagger version