103 Commits

Author SHA1 Message Date
Davide Bianchi
24dfb293ea Upgrade version to v0.6.0 2022-11-04 15:15:01 +01:00
Davide Bianchi
a5b9bd3dc4 Merge pull request #86 from davidebianchi/feat/tags-support-in-add-routes 2022-11-04 15:10:02 +01:00
Federico Maggi
7f7c92eaca feat: tags support 2022-11-04 15:01:26 +01:00
Davide Bianchi
9fac38a162 fix 2022-10-03 09:18:13 +02:00
Davide Bianchi
424779a7d8 Upgrade version to v0.5.1 2022-10-03 09:17:33 +02:00
Davide Bianchi
d6a528ea28 fix: changelog 2022-10-03 09:17:25 +02:00
Davide Bianchi
909c58608a upgrade deps 2022-10-03 09:17:02 +02:00
Davide Bianchi
43c6e37a47 Merge pull request #78 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.103.0 2022-10-03 09:14:37 +02:00
dependabot[bot]
b9dc8ff83c chore(deps): bump github.com/getkin/kin-openapi from 0.102.0 to 0.103.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.102.0 to 0.103.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.102.0...v0.103.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-09-22 03:20:06 +00:00
Davide Bianchi
1b95853d11 Merge pull request #77 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.102.0 2022-09-20 21:44:58 +02:00
Davide Bianchi
e8369933fc Merge pull request #74 from davidebianchi/dependabot/go_modules/github.com/labstack/echo/v4-4.9.0 2022-09-20 21:44:24 +02:00
dependabot[bot]
89d668771a chore(deps): bump github.com/getkin/kin-openapi from 0.98.0 to 0.102.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.98.0 to 0.102.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.98.0...v0.102.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-09-19 03:08:43 +00:00
dependabot[bot]
0039a3f74f chore(deps): bump github.com/labstack/echo/v4 from 4.7.2 to 4.9.0
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.7.2 to 4.9.0.
- [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.7.2...v4.9.0)

---
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>
2022-09-05 13:15:57 +00:00
Davide Bianchi
b29887d15f docs: update CHANGELOG 2022-08-05 17:56:20 +02:00
Davide Bianchi
e03aeb51c2 update deps 2022-08-05 17:55:39 +02:00
Davide Bianchi
a3cb8e3775 Merge pull request #68 from davidebianchi/dependabot/go_modules/github.com/invopop/jsonschema-0.6.0 2022-08-05 17:54:31 +02:00
Davide Bianchi
995c3d97a2 Merge pull request #70 from davidebianchi/autofill-path-params 2022-08-05 17:52:46 +02:00
Davide Bianchi
d376b5411e Update README.md 2022-08-05 17:48:09 +02:00
Davide Bianchi
b187bd716f docs: update CHANGELOG 2022-08-05 17:44:50 +02:00
Davide Bianchi
d07b9c96f5 feat: autofill path params 2022-08-05 17:35:30 +02:00
dependabot[bot]
3c8cffc622 chore(deps): bump github.com/invopop/jsonschema from 0.5.0 to 0.6.0
Bumps [github.com/invopop/jsonschema](https://github.com/invopop/jsonschema) from 0.5.0 to 0.6.0.
- [Release notes](https://github.com/invopop/jsonschema/releases)
- [Commits](https://github.com/invopop/jsonschema/compare/v0.5.0...v0.6.0)

---
updated-dependencies:
- dependency-name: github.com/invopop/jsonschema
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-04 03:12:40 +00:00
Davide Bianchi
c5e3219f7a docs: update CHANGELOG 2022-08-02 09:15:52 +02:00
Davide Bianchi
d9c105585b Merge pull request #53 from davidebianchi/upgrade-deps 2022-08-02 09:13:59 +02:00
Davide Bianchi
3f7d09cc36 improve changelog 2022-08-02 09:11:28 +02:00
Davide Bianchi
57842cf39d upgrade deps 2022-08-02 09:08:04 +02:00
Davide Bianchi
3e359451c8 Merge pull request #66 from davidebianchi/dependabot/go_modules/github.com/stretchr/testify-1.8.0 2022-08-01 08:58:28 +02:00
dependabot[bot]
7896d8efd3 chore(deps): bump github.com/stretchr/testify from 1.7.5 to 1.8.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.5 to 1.8.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.5...v1.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-30 03:16:40 +00:00
Davide Bianchi
ac9ae09ff9 Merge pull request #57 from davidebianchi/dependabot/go_modules/github.com/labstack/echo/v4-4.7.2
chore(deps): bump github.com/labstack/echo/v4 from 4.6.3 to 4.7.2
2022-06-25 08:29:04 +02:00
dependabot[bot]
42bfc9c9a6 chore(deps): bump github.com/labstack/echo/v4 from 4.6.3 to 4.7.2
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.6.3 to 4.7.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.6.3...v4.7.2)

---
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>
2022-06-25 06:23:31 +00:00
Davide Bianchi
32233b0a6b Merge pull request #65 from davidebianchi/dependabot/go_modules/github.com/stretchr/testify-1.7.5
chore(deps): bump github.com/stretchr/testify from 1.7.2 to 1.7.5
2022-06-25 08:22:06 +02:00
dependabot[bot]
ab052edbe2 chore(deps): bump github.com/stretchr/testify from 1.7.2 to 1.7.5
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.2 to 1.7.5.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.2...v1.7.5)

---
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>
2022-06-24 03:09:17 +00:00
Davide Bianchi
90b7305b57 Merge pull request #62 from davidebianchi/dependabot/go_modules/github.com/stretchr/testify-1.7.2
chore(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.2
2022-06-18 23:53:57 +02:00
dependabot[bot]
0a6ddb22c3 chore(deps): bump github.com/stretchr/testify from 1.7.0 to 1.7.2
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.7.0 to 1.7.2.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.7.0...v1.7.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>
2022-06-07 03:11:22 +00:00
Davide Bianchi
e884893fd5 chore: remove support to go 1.15 2022-03-26 18:34:24 +01:00
Davide Bianchi
1aaf503686 upgrade deps 2022-03-26 18:20:16 +01:00
Davide Bianchi
f109edd60a feat: upgrade deps 2022-03-12 19:13:02 +01:00
Davide Bianchi
d187894847 Merge pull request #49 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.89.0 2022-02-04 09:52:46 +01:00
dependabot[bot]
6eeb5ab409 chore(deps): bump github.com/getkin/kin-openapi from 0.88.0 to 0.89.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.88.0 to 0.89.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.88.0...v0.89.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-02-04 03:12:31 +00:00
Davide Bianchi
8efc400a2f Merge pull request #48 from davidebianchi/dependabot/go_modules/github.com/labstack/echo/v4-4.6.3 2022-02-02 22:41:50 +01:00
dependabot[bot]
5c5d02c68e chore(deps): bump github.com/labstack/echo/v4 from 4.6.1 to 4.6.3
Bumps [github.com/labstack/echo/v4](https://github.com/labstack/echo) from 4.6.1 to 4.6.3.
- [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.6.1...v4.6.3)

---
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>
2022-01-11 03:16:28 +00:00
Davide Bianchi
e5b47a772a Merge pull request #46 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.88.0 2022-01-05 18:25:13 +01:00
dependabot[bot]
fa6f33399b chore(deps): bump github.com/getkin/kin-openapi from 0.87.0 to 0.88.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.87.0 to 0.88.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.87.0...v0.88.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-01-05 03:13:39 +00:00
Davide Bianchi
786a5ed67d Merge pull request #45 from davidebianchi/echo-integration-example 2022-01-04 15:40:12 +01:00
Davide Bianchi
8f8ca16724 test: add subrouter test 2021-12-27 19:45:53 +01:00
Davide Bianchi
e1e3e95d80 feat: add test of integration of echo router 2021-12-22 19:13:18 +01:00
Davide Bianchi
1f550922b6 Merge pull request #44 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.87.0 2021-12-21 22:57:20 +01:00
dependabot[bot]
55cfa361ce chore(deps): bump github.com/getkin/kin-openapi from 0.86.0 to 0.87.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.86.0 to 0.87.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.86.0...v0.87.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>
2021-12-21 03:09:22 +00:00
Davide Bianchi
0c867d2839 fix: change test name 2021-12-20 20:32:39 +01:00
Davide Bianchi
68fdf59cdb change go version to 1.17 and update workflow to support from go version 1.15 to 1.17 2021-12-20 20:31:46 +01:00
Davide Bianchi
ebb8822041 Merge pull request #42 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.86.0 2021-12-20 20:28:23 +01:00
Davide Bianchi
491f683807 fix: update CHANGELOG 2021-12-20 20:25:58 +01:00
Davide Bianchi
122be38154 Merge pull request #39 from danibix95/fix/align-code-docs 2021-12-20 20:21:53 +01:00
dependabot[bot]
a0ea89ed92 chore(deps): bump github.com/getkin/kin-openapi from 0.85.0 to 0.86.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.85.0 to 0.86.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.85.0...v0.86.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>
2021-12-13 03:14:25 +00:00
Davide Bianchi
f21942de1b Merge pull request #41 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.85.0 2021-12-06 22:34:19 +01:00
dependabot[bot]
b1b7025862 chore(deps): bump github.com/getkin/kin-openapi from 0.79.0 to 0.85.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.79.0 to 0.85.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.79.0...v0.85.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>
2021-12-06 03:12:57 +00:00
danibix95
3d21dece34 Set method as first parameter of AddRoute function in Router interface 2021-11-23 23:19:52 +01:00
Davide Bianchi
715c554482 docs: update README 2021-11-10 11:26:34 +01:00
Davide Bianchi
d35432abaf test: add integration test 2021-11-10 11:19:12 +01:00
Davide Bianchi
ffb0e6b3f7 docs: update CHANGELOG 2021-11-10 10:41:38 +01:00
Davide Bianchi
94abd8f4bf docs: update README 2021-11-10 10:39:59 +01:00
Davide Bianchi
7232d5d823 feat: add coverage report 2021-11-10 10:34:38 +01:00
Davide Bianchi
b26ddbeecf Update test-builds.yml 2021-11-10 10:30:40 +01:00
Davide Bianchi
3374e2bd80 Merge pull request #36 from davidebianchi/feat/subrouter-path-prefix 2021-11-10 10:27:22 +01:00
Davide Bianchi
33d81e9cdd docs: update CHANGELOG 2021-11-10 10:23:17 +01:00
Davide Bianchi
a7a671be5a test: add route with path equal to prefix path 2021-11-10 10:22:45 +01:00
Davide Bianchi
239a70a1a0 test: more simple test 2021-11-10 10:15:55 +01:00
Davide Bianchi
8c0aacb68c fix: remove GetSwaggerSchema fn 2021-11-10 10:13:51 +01:00
Davide Bianchi
d145c6ca5d feat: add SubRouter method 2021-11-10 10:12:26 +01:00
Davide Bianchi
a8c5be8870 feat: add SubRouter method 2021-11-10 10:02:32 +01:00
Davide Bianchi
8fda85d9d3 docs: update CHANGELOG 2021-11-09 22:36:56 +01:00
Davide Bianchi
a872dd02b7 feat: add support to subrouter, handle path prefix 2021-11-09 22:35:17 +01:00
Davide Bianchi
7615365291 docs: update CHANGELOG 2021-10-16 21:59:57 +02:00
Davide Bianchi
6411ef6e66 Merge branch 'main' of github.com:davidebianchi/gswagger 2021-10-16 21:59:03 +02:00
Davide Bianchi
49fd48c375 docs: update README 2021-10-16 21:58:54 +02:00
Davide Bianchi
9f3698cf59 Update README.md 2021-10-16 21:54:37 +02:00
Davide Bianchi
98ed6678e6 Update README.md 2021-10-16 21:54:28 +02:00
Davide Bianchi
0075df7fc4 Update README.md 2021-10-16 21:39:21 +02:00
Davide Bianchi
66b593f3f6 Update README.md 2021-10-16 21:38:58 +02:00
Davide Bianchi
30bf3ec60e docs: change readme 2021-10-16 21:01:59 +02:00
Davide Bianchi
ff30e87701 Merge pull request #33 from davidebianchi/support-router-interface 2021-10-16 21:00:23 +02:00
Davide Bianchi
07568cabc0 test: fix test 2021-10-16 20:59:27 +02:00
Davide Bianchi
2cffb94971 feat: improve documentation 2021-10-16 20:56:15 +02:00
Davide Bianchi
ec86fe1571 docs: improved docs 2021-10-16 20:12:39 +02:00
Davide Bianchi
5d1b1b795d fix: remove first level export of new router 2021-10-16 20:03:18 +02:00
Davide Bianchi
b964b3c3ca feat: support custom router interface 2021-10-16 20:00:52 +02:00
Davide Bianchi
4e8ccbd66d fix: fix warning in test 2021-10-16 19:27:48 +02:00
Davide Bianchi
9aaf041909 Merge pull request #32 from davidebianchi/upgrade-deps 2021-10-16 19:25:27 +02:00
Davide Bianchi
b1dc480411 run go mod tidy 2021-10-16 19:24:31 +02:00
Davide Bianchi
3d9ad0fb5f feat: upgrade deps 2021-10-16 19:23:52 +02:00
Davide Bianchi
5f07fcb394 Update README.md 2021-10-16 19:05:25 +02:00
Davide Bianchi
985e3dfd03 Update dependabot.yml 2021-10-16 19:04:21 +02:00
Davide Bianchi
67073bb3bb Merge pull request #30 from davidebianchi/dependabot/add-v2-config-file
Upgrade to GitHub-native Dependabot
2021-05-18 21:44:48 +02:00
dependabot-preview[bot]
ba069411b1 Upgrade to GitHub-native Dependabot 2021-04-29 16:07:20 +00:00
Davide Bianchi
a950dcc879 Merge pull request #28 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.60.0
chore(deps): bump github.com/getkin/kin-openapi from 0.53.0 to 0.60.0
2021-04-26 18:54:00 +02:00
dependabot-preview[bot]
1fe64517bd chore(deps): bump github.com/getkin/kin-openapi from 0.53.0 to 0.60.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.53.0 to 0.60.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.53.0...v0.60.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-04-26 06:34:55 +00:00
Davide Bianchi
651f2d0478 Merge pull request #25 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.53.0
chore(deps): bump github.com/getkin/kin-openapi from 0.48.0 to 0.53.0
2021-04-03 18:57:28 +02:00
dependabot-preview[bot]
22cf8cdbc4 chore(deps): bump github.com/getkin/kin-openapi from 0.48.0 to 0.53.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.48.0 to 0.53.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.48.0...v0.53.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-24 06:58:26 +00:00
Davide Bianchi
2d310b15e1 Merge pull request #21 from davidebianchi/dependabot/go_modules/github.com/getkin/kin-openapi-0.48.0
chore(deps): bump github.com/getkin/kin-openapi from 0.39.0 to 0.48.0
2021-03-07 18:14:05 +01:00
dependabot-preview[bot]
b77a71d0e4 chore(deps): bump github.com/getkin/kin-openapi from 0.39.0 to 0.48.0
Bumps [github.com/getkin/kin-openapi](https://github.com/getkin/kin-openapi) from 0.39.0 to 0.48.0.
- [Release notes](https://github.com/getkin/kin-openapi/releases)
- [Commits](https://github.com/getkin/kin-openapi/compare/v0.39.0...v0.48.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-05 07:01:19 +00:00
Davide Bianchi
7f240250d5 Create CHANGELOG.md 2021-02-07 18:19:23 +01:00
Davide Bianchi
3b0f5b33eb Merge pull request #15 from davidebianchi/dependabot/go_modules/github.com/stretchr/testify-1.7.0
chore(deps): bump github.com/stretchr/testify from 1.6.1 to 1.7.0
2021-02-07 18:17:45 +01:00
dependabot-preview[bot]
6c8a4b5cdf chore(deps): bump github.com/stretchr/testify from 1.6.1 to 1.7.0
Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.6.1 to 1.7.0.
- [Release notes](https://github.com/stretchr/testify/releases)
- [Commits](https://github.com/stretchr/testify/compare/v1.6.1...v1.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-02-07 17:04:21 +00:00
Davide Bianchi
04774f8ed5 update deps 2021-02-07 18:02:52 +01:00
22 changed files with 957 additions and 157 deletions

7
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: gomod
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10

View File

@@ -5,28 +5,35 @@ on:
push:
jobs:
tests:
name: Test on go ${{ matrix.go_version }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
go_version: [1.15]
os: [macos-latest, ubuntu-latest]
steps:
- uses: actions/checkout@v1
- name: Use golang ${{ matrix.go_version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go_version }}
name: Test on go ${{ matrix.go_version }} os ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
go_version: [1.16, 1.17]
os: [ubuntu-latest]
include:
- go_version: 1.17
os: macos-latest
steps:
- uses: actions/checkout@v1
- name: Use golang ${{ matrix.go_version }}
uses: actions/setup-go@v1
with:
go-version: ${{ matrix.go_version }}
- name: Go version
run: |
go version
- name: Go get dependencies
run: |
go get -v -t -d ./...
- name: Run tests
run: |
go test ./... -count=1 -race -cover
- name: Build
run: |
go build -v .
- name: Go version
run: |
go version
- name: Go get dependencies
run: |
go get -v -t -d ./...
- name: Run tests
run: |
go test ./... -count=1 -race -cover -coverprofile cover.out
- name: Build
run: |
go build -v .
- name: Send the coverage output
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: cover.out

84
CHANGELOG.md Normal file
View File

@@ -0,0 +1,84 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
## 0.6.0 - 04-11-2022
### Added
- Tags support to `router.AddRoute` accepted definition
## 0.5.1 - 03-10-2022
### Fixed
- upgrade deps
## v0.5.0 - 05-08-2022
### Added
- path params are auto generated if not set
## v0.4.0 - 02-08-2022
### Changed
- change jsonschema lib to `invopop/jsonschema v0.5.0`. This updates remove the `additionalProperties: true` from all the schemas, as it is the default value
### BREAKING CHANGES
- modified Router interface by sorting addRoute arguments in a different manner: first method and then path
To migrate, all the router implementation must be updated with the Router interface change.
Before:
```go
type Router interface {
AddRoute(path, method string, handler HandlerFunc) Route
}
```
After:
```go
type Router interface {
AddRoute(method, path string, handler HandlerFunc) Route
}
```
### Updates
- kin-openapi@v0.98.0
- go-openapi/swag@v0.21.1
- labstack/echo/v4@v4.7.2
## v0.3.0 - 10-11-2021
### Added
- handle router with path prefix
- add SubRouter method to use a new sub router
## v0.2.0 - 16-10-2021
### BREAKING CHANGES
Introduced the `apirouter.Router` interface, which abstract the used router.
Changed function are:
- Router struct now support `apirouter.Router` interface
- NewRouter function accepted router is an `apirouter.Router`
- AddRawRoute now accept `apirouter.Handler` iterface
- AddRawRoute returns an interface instead of *mux.Router. This interface is the Route returned by specific Router
- AddRoute now accept `apirouter.Handler` iterface
- AddRoute returns an interface instead of *mux.Router. This interface is the Route returned by specific Router
## v0.1.0
Initial release

24
Makefile Normal file
View File

@@ -0,0 +1,24 @@
VERSION ?= latest
# Create a variable that contains the current date in UTC
# Different flow if this script is running on Darwin or Linux machines.
ifeq (Darwin,$(shell uname))
NOW_DATE = $(shell date -u +%d-%m-%Y)
else
NOW_DATE = $(shell date -u -I)
endif
all: test
.PHONY: test
test:
go test ./... -coverprofile coverage.out
$(MAKE) clean
.PHONY: version
version:
sed -i.bck "s|## Unreleased|## Unreleased\n\n## ${VERSION} - ${NOW_DATE}|g" "CHANGELOG.md"
rm -fr "CHANGELOG.md.bck"
git add "CHANGELOG.md"
git commit -m "Upgrade version to v${VERSION}"
git tag v${VERSION}

108
README.md
View File

@@ -1,34 +1,43 @@
<div align="center">
[![Build Status][github-actions-svg]][github-actions]
[![Coverage Status](https://coveralls.io/repos/github/davidebianchi/gswagger/badge.svg?branch=main)](https://coveralls.io/github/davidebianchi/gswagger?branch=main)
[![Go Report Card][go-report-card]][go-report-card-link]
[![GoDoc][godoc-svg]][godoc-link]
# Gorilla Swagger
# gswagger
</div>
Generate a swagger dynamically based on the types used to handle request and response.
Generate an openapi spec dynamically based on the types used to handle request and response.
It works with [gorilla-mux](https://github.com/gorilla/mux) and uses [kin-openapi]
to automatically generate and serve a swagger file.
It works with any router which support handler net/http HandlerFunc compatible.
The routers supported out of the box are:
- [gorilla-mux](https://github.com/gorilla/mux)
This lib uses [kin-openapi] to automatically generate and serve a swagger file.
To convert struct to schemas, we use [jsonschema] library.
The struct must contains the appropriate struct tags to be inserted in json schema to generate the schema dynamically.
It is always possible to add a totally custom swagger schema using [kin-openapi]
It is always possible to add a totally custom swagger schema using [kin-openapi].
## Usage
An example usage of this lib:
To add a router not handled out of the box, it must implements the [Router interface](./apirouter/router.go).
An example usage of this lib with gorilla mux:
```go
context := context.Background()
r := mux.NewRouter()
router, _ := swagger.NewRouter(r, gswagger.Options{
muxRouter := mux.NewRouter()
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), swagger.Options{
Context: context,
Openapi: &openapi3.Swagger{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "my swagger title",
Title: "my title",
Version: "1.0.0",
},
},
@@ -39,20 +48,31 @@ okHandler := func(w http.ResponseWriter, req *http.Request) {
w.Write([]byte("OK"))
}
router.AddRoute(http.MethodPost, "/users", okHandler, Definitions{
RequestBody: &gswagger.ContentValue{
Content: gswagger.Content{
type User struct {
Name string `json:"name" jsonschema:"title=The user name,required" jsonschema_extras:"example=Jane"`
PhoneNumber int `json:"phone" jsonschema:"title=mobile number of user"`
Groups []string `json:"groups,omitempty" jsonschema:"title=groups of the user,default=users"`
Address string `json:"address" jsonschema:"title=user address"`
}
type Users []User
type errorResponse struct {
Message string `json:"message"`
}
router.AddRoute(http.MethodPost, "/users", okHandler, swagger.Definitions{
RequestBody: &swagger.ContentValue{
Content: swagger.Content{
"application/json": {Value: User{}},
},
},
Responses: map[int]gswagger.ContentValue{
Responses: map[int]swagger.ContentValue{
201: {
Content: gswagger.Content{
Content: swagger.Content{
"text/html": {Value: ""},
},
},
401: {
Content: gswagger.Content{
Content: swagger.Content{
"application/json": {Value: &errorResponse{}},
},
Description: "invalid request",
@@ -60,11 +80,11 @@ router.AddRoute(http.MethodPost, "/users", okHandler, Definitions{
},
})
router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Responses: map[int]ContentValue{
router.AddRoute(http.MethodGet, "/users", okHandler, swagger.Definitions{
Responses: map[int]swagger.ContentValue{
200: {
Content: Content{
"application/json": {Value: &Users{}},
Content: swagger.Content{
"application/json": {Value: &[]User{}},
},
},
},
@@ -81,7 +101,46 @@ operation.AddRequestBody(requestBody)
router.AddRawRoute(http.MethodPost, "/cars", okHandler, operation)
```
This configuration will output the schema shown [here](testdata/users_employees.json)
This configuration will output the schema shown [here](testdata/users_employees.json).
## Auto generated path params schema
The path params, if not set in schema, are auto generated from the path. Currently, it is supported only the path params like `{myPath}`.
For example, with this use case:
```golang
okHandler := func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("OK"))
}
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
Querystring: ParameterValue{
"query": {
Schema: &Schema{Value: ""},
},
},
})
require.NoError(t, err)
_, err = router.AddRoute(http.MethodGet, "/cars/{carId}/drivers/{driverId}", okHandler, Definitions{})
require.NoError(t, err)
```
The generated oas schema will contains `userId`, `carId` and `driverId` as path params set to string.
If only one params is set, you must specify manually all the path params.
The generated file for this test case is [here](./testdata/params-autofill.json).
## SubRouter
It is possible to create a new sub router from the swagger.Router.
It is possible to add a prefix to all the routes created under the specific router (instead of use the router specific methods, if given, or repeat the prefix for every route).
It could also be useful if you need a sub router to create a group of APIs which use the same middleware (for example,this could be achieved by the SubRouter features of gorilla mux, for example).
To see the SubRouter example, please see the [SubRouter test](./integration_test.go).
### FAQ
@@ -101,7 +160,7 @@ You can create manually a swagger with `oneOf` using the `AddRawRoute` method, o
*Formats*:
* `uuid` is unsupported by [kin-openapi]
- `uuid` is unsupported by [kin-openapi]
## Versioning
@@ -110,10 +169,11 @@ see the [tags on this repository](https://github.com/davidebianchi/gswagger/tags
<!-- Reference -->
[kin-openapi]: https://github.com/getkin/kin-openapi
[jsonschema]: https://github.com/alecthomas/jsonschema
[jsonschema]: https://github.com/invopop/jsonschemaa
[github-actions]: https://github.com/davidebianchi/gswagger/actions
[github-actions-svg]: https://github.com/davidebianchi/gswagger/workflows/Test%20and%20build/badge.svg
[godoc-svg]: https://godoc.org/github.com/davidebianchi/gswagger?status.svg
[godoc-link]: https://godoc.org/github.com/davidebianchi/gswagger
[go-report-card]: https://goreportcard.com/badge/github.com/davidebianchi/gswagger
[go-report-card-link]: https://goreportcard.com/report/github.com/davidebianchi/gswagger
[semver]: https://semver.org/

17
apirouter/gorilla.go Normal file
View File

@@ -0,0 +1,17 @@
package apirouter
import "github.com/gorilla/mux"
type gorillaRouter struct {
router *mux.Router
}
func (r gorillaRouter) AddRoute(method string, path string, handler HandlerFunc) Route {
return r.router.HandleFunc(path, handler).Methods(method)
}
func NewGorillaMuxRouter(router *mux.Router) Router {
return gorillaRouter{
router: router,
}
}

47
apirouter/gorilla_test.go Normal file
View File

@@ -0,0 +1,47 @@
package apirouter
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
)
func TestGorillaMuxRouter(t *testing.T) {
muxRouter := mux.NewRouter()
ar := NewGorillaMuxRouter(muxRouter)
t.Run("create a new api router", func(t *testing.T) {
require.Implements(t, (*Router)(nil), ar)
})
t.Run("add new route", func(t *testing.T) {
route := ar.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(200)
w.Write(nil)
})
_, ok := route.(*mux.Route)
require.True(t, ok)
t.Run("router exposes correctly api", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/foo", nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
})
t.Run("router exposes api only to the specific method", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPost, "/foo", nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusMethodNotAllowed, w.Result().StatusCode)
})
})
}

12
apirouter/router.go Normal file
View File

@@ -0,0 +1,12 @@
package apirouter
import "net/http"
// Handler is the http type handler
type HandlerFunc func(w http.ResponseWriter, req *http.Request)
type Router interface {
AddRoute(method string, path string, handler HandlerFunc) Route
}
type Route interface{}

33
go.mod
View File

@@ -1,13 +1,34 @@
module github.com/davidebianchi/gswagger
go 1.15
go 1.17
require (
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add
github.com/getkin/kin-openapi v0.35.0
github.com/getkin/kin-openapi v0.103.0
github.com/ghodss/yaml v1.0.0
github.com/go-openapi/swag v0.19.13 // indirect
github.com/go-openapi/swag v0.21.1 // indirect
github.com/gorilla/mux v1.8.0
github.com/iancoleman/orderedmap v0.1.0 // indirect
github.com/stretchr/testify v1.6.1
github.com/iancoleman/orderedmap v0.2.0 // indirect
github.com/invopop/jsonschema v0.6.0
github.com/labstack/echo/v4 v4.9.0
github.com/mailru/easyjson v0.7.7 // indirect
github.com/stretchr/testify v1.8.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/invopop/yaml v0.2.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/labstack/gommon v0.3.1 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.1 // indirect
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 // indirect
golang.org/x/text v0.3.7 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

82
go.sum
View File

@@ -1,26 +1,27 @@
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add h1:UWj2AVW7oygpatGgJRy6rvNBcl+J7u8vl6qTV+XNWzA=
github.com/alecthomas/jsonschema v0.0.0-20201129101101-7b852d451add/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/getkin/kin-openapi v0.35.0 h1:YoJusew7Es36hSpnEx3gRL2DGj/82T3j3Akbs9VIXDQ=
github.com/getkin/kin-openapi v0.35.0/go.mod h1:ZJSfy1PxJv2QQvH9EdBj3nupRTVvV42mkW6zKUlRBwk=
github.com/getkin/kin-openapi v0.103.0 h1:F5wAtaQvPWxKCAYZ69LgHAThgu16p4u41VQtbn1U8LA=
github.com/getkin/kin-openapi v0.103.0/go.mod h1:w4lRPHiyOdwGbOkLIyk+P0qCwlu7TXPCHD/64nSXzgE=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.13 h1:233UVgMy1DlmCYYfOiFpta6e2urloh+sEs5id6lyzog=
github.com/go-openapi/swag v0.19.13/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/orderedmap v0.1.0 h1:2orAxZBJsvimgEBmMWfXaFlzSG2fbQil5qzP3F6cCkg=
github.com/iancoleman/orderedmap v0.1.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/iancoleman/orderedmap v0.2.0 h1:sq1N/TFpYH++aViPcaKjys3bDClUEU7s5B+z6jq8pNA=
github.com/iancoleman/orderedmap v0.2.0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
github.com/invopop/jsonschema v0.6.0 h1:8e+xY8ZEn8gDHUYylSlLHy22P+SLeIRIHv3nM3hCbmY=
github.com/invopop/jsonschema v0.6.0/go.mod h1:O9uiLokuu0+MGFlyiaqtWxwqJm41/+8Nj0lD7A36YH0=
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@@ -28,34 +29,73 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.9.0 h1:wPOF1CE6gvt/kmbMR4dGzWvHMPT+sAEUJOwOTtvITVY=
github.com/labstack/echo/v4 v4.9.0/go.mod h1:xkCDAdFCIf8jsFQ5NnbK7oqaF/yU1A1X20Ltm0OvSks=
github.com/labstack/gommon v0.3.1 h1:OomWaJXm7xR6L1HmEtGyQf26TEn7V6X88mktX9kee9o=
github.com/labstack/gommon v0.3.1/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1 h1:TVEnxayobAdVkhQfrfes2IzOB6o+z4roRkPF52WA1u4=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc h1:i6Z9eOQAdM7lvsbkT3fwFNtSAAC+A59TYilFj53HW+E=
golang.org/x/crypto v0.0.0-20220312131142-6068a2e6cfdc/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@@ -1,4 +1,4 @@
package swagger
package swagger_test
import (
"context"
@@ -8,8 +8,11 @@ import (
"net/http/httptest"
"testing"
swagger "github.com/davidebianchi/gswagger"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/require"
)
@@ -20,7 +23,7 @@ const (
func TestIntegration(t *testing.T) {
t.Run("router works correctly", func(t *testing.T) {
muxRouter := setupSwagger(t)
muxRouter, _ := setupSwagger(t)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
@@ -34,7 +37,7 @@ func TestIntegration(t *testing.T) {
t.Run("and generate swagger", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, DefaultJSONDocumentationPath, nil)
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
muxRouter.ServeHTTP(w, r)
@@ -44,6 +47,125 @@ func TestIntegration(t *testing.T) {
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
})
})
t.Run("router works correctly - echo", func(t *testing.T) {
echoRouter, _ := setupEchoSwagger(t)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
echoRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "OK", body)
t.Run("and generate swagger", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
echoRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
})
})
t.Run("works correctly with subrouter - handles path prefix - gorilla mux", func(t *testing.T) {
muxRouter, swaggerRouter := setupSwagger(t)
muxSubRouter := muxRouter.NewRoute().Subrouter()
subRouter, err := swaggerRouter.SubRouter(apirouter.NewGorillaMuxRouter(muxSubRouter), swagger.SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
require.NoError(t, err)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "OK", body)
t.Run("correctly call sub router", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/prefix/foo", nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "OK", body)
})
t.Run("and generate swagger", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
muxRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
})
})
t.Run("works correctly with subrouter - handles path prefix - echo", func(t *testing.T) {
eRouter, swaggerRouter := setupEchoSwagger(t)
subRouter, err := swaggerRouter.SubRouter(echoRouter{router: eRouter}, swagger.SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subRouter.AddRoute(http.MethodGet, "/foo", okHandler, swagger.Definitions{})
require.NoError(t, err)
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/hello", nil)
eRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "OK", body)
t.Run("correctly call sub router", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, "/prefix/foo", nil)
eRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "OK", body)
})
t.Run("and generate swagger", func(t *testing.T) {
w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodGet, swagger.DefaultJSONDocumentationPath, nil)
eRouter.ServeHTTP(w, r)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
body := readBody(t, w.Result().Body)
require.Equal(t, "{\"components\":{},\"info\":{\"title\":\"test swagger title\",\"version\":\"test swagger version\"},\"openapi\":\"3.0.0\",\"paths\":{\"/hello\":{\"get\":{\"responses\":{\"default\":{\"description\":\"\"}}}}}}", body)
})
})
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {
@@ -55,15 +177,15 @@ func readBody(t *testing.T, requestBody io.ReadCloser) string {
return string(body)
}
func setupSwagger(t *testing.T) *mux.Router {
func setupSwagger(t *testing.T) (*mux.Router, *swagger.Router) {
t.Helper()
context := context.Background()
muxRouter := mux.NewRouter()
router, err := NewRouter(muxRouter, Options{
router, err := swagger.NewRouter(apirouter.NewGorillaMuxRouter(muxRouter), swagger.Options{
Context: context,
Openapi: &openapi3.Swagger{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: swaggerOpenapiTitle,
Version: swaggerOpenapiVersion,
@@ -72,17 +194,61 @@ func setupSwagger(t *testing.T) *mux.Router {
})
require.NoError(t, err)
handler := func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`OK`))
}
operation := Operation{}
operation := swagger.Operation{}
_, err = router.AddRawRoute(http.MethodGet, "/hello", handler, operation)
_, err = router.AddRawRoute(http.MethodGet, "/hello", okHandler, operation)
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
return muxRouter
return muxRouter, router
}
func okHandler(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`OK`))
}
func setupEchoSwagger(t *testing.T) (*echo.Echo, *swagger.Router) {
t.Helper()
context := context.Background()
e := echo.New()
router, err := swagger.NewRouter(echoRouter{router: e}, swagger.Options{
Context: context,
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: swaggerOpenapiTitle,
Version: swaggerOpenapiVersion,
},
},
})
require.NoError(t, err)
operation := swagger.Operation{}
_, err = router.AddRawRoute(http.MethodGet, "/hello", func(w http.ResponseWriter, req *http.Request) {
ctx := e.NewContext(req, w)
echoOkHandler(ctx)
}, operation)
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
return e, router
}
func echoOkHandler(c echo.Context) error {
return c.String(http.StatusOK, "OK")
}
type echoRouter struct {
router *echo.Echo
}
func (r echoRouter) AddRoute(method, path string, handler apirouter.HandlerFunc) apirouter.Route {
return r.router.Add(method, path, echo.WrapHandler(http.HandlerFunc(handler)))
}

43
main.go
View File

@@ -7,9 +7,9 @@ import (
"net/http"
"strings"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/ghodss/yaml"
"github.com/gorilla/mux"
)
var (
@@ -27,27 +27,32 @@ const (
defaultOpenapiVersion = "3.0.0"
)
// Router handle the gorilla mux router and the swagger schema
// Router handle the api router and the swagger schema.
// api router supported out of the box are:
// - gorilla mux
type Router struct {
router *mux.Router
swaggerSchema *openapi3.Swagger
router apirouter.Router
swaggerSchema *openapi3.T
context context.Context
jsonDocumentationPath string
yamlDocumentationPath string
pathPrefix string
}
// Options to be passed to create the new router and swagger
type Options struct {
Context context.Context
Openapi *openapi3.Swagger
Openapi *openapi3.T
// JSONDocumentationPath is the path exposed by json endpoint. Default to /documentation/json.
JSONDocumentationPath string
// YAMLDocumentationPath is the path exposed by yaml endpoint. Default to /documentation/yaml.
YAMLDocumentationPath string
// Add path prefix to add to every router path.
PathPrefix string
}
// NewRouter generate new router with swagger. Default to OpenAPI 3.0.0
func NewRouter(router *mux.Router, options Options) (*Router, error) {
func NewRouter(router apirouter.Router, options Options) (*Router, error) {
swagger, err := generateNewValidSwagger(options.Openapi)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrValidatingSwagger, err)
@@ -80,10 +85,26 @@ func NewRouter(router *mux.Router, options Options) (*Router, error) {
context: ctx,
yamlDocumentationPath: yamlDocumentationPath,
jsonDocumentationPath: jsonDocumentationPath,
pathPrefix: options.PathPrefix,
}, nil
}
func generateNewValidSwagger(swagger *openapi3.Swagger) (*openapi3.Swagger, error) {
type SubRouterOptions struct {
PathPrefix string
}
func (r Router) SubRouter(router apirouter.Router, opts SubRouterOptions) (*Router, error) {
return &Router{
router: router,
swaggerSchema: r.swaggerSchema,
context: r.context,
jsonDocumentationPath: r.jsonDocumentationPath,
yamlDocumentationPath: r.yamlDocumentationPath,
pathPrefix: opts.PathPrefix,
}, nil
}
func generateNewValidSwagger(swagger *openapi3.T) (*openapi3.T, error) {
if swagger == nil {
return nil, fmt.Errorf("swagger is required")
}
@@ -118,21 +139,21 @@ func (r Router) GenerateAndExposeSwagger() error {
if err != nil {
return fmt.Errorf("%w json marshal: %s", ErrGenerateSwagger, err)
}
r.router.HandleFunc(r.jsonDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
r.router.AddRoute(http.MethodGet, r.jsonDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(jsonSwagger)
}).Methods(http.MethodGet)
})
yamlSwagger, err := yaml.JSONToYAML(jsonSwagger)
if err != nil {
return fmt.Errorf("%w yaml marshal: %s", ErrGenerateSwagger, err)
}
r.router.HandleFunc(r.yamlDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
r.router.AddRoute(http.MethodGet, r.yamlDocumentationPath, func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
w.Write(yamlSwagger)
}).Methods(http.MethodGet)
})
return nil
}

View File

@@ -3,45 +3,48 @@ package swagger
import (
"context"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
)
func TestNewRouter(t *testing.T) {
mRouter := mux.NewRouter()
muxRouter := mux.NewRouter()
mAPIRouter := apirouter.NewGorillaMuxRouter(muxRouter)
info := &openapi3.Info{
Title: "my title",
Version: "my version",
}
openapi := &openapi3.Swagger{
openapi := &openapi3.T{
Info: info,
Paths: openapi3.Paths{},
}
t.Run("not ok - invalid Openapi option", func(t *testing.T) {
r, err := NewRouter(mRouter, Options{})
r, err := NewRouter(mAPIRouter, Options{})
require.Nil(t, r)
require.EqualError(t, err, fmt.Sprintf("%s: swagger is required", ErrValidatingSwagger))
})
t.Run("ok - with default context", func(t *testing.T) {
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
})
require.NoError(t, err)
require.Equal(t, &Router{
context: context.Background(),
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: DefaultJSONDocumentationPath,
yamlDocumentationPath: DefaultYAMLDocumentationPath,
@@ -51,7 +54,7 @@ func TestNewRouter(t *testing.T) {
t.Run("ok - with custom context", func(t *testing.T) {
type key struct{}
ctx := context.WithValue(context.Background(), key{}, "value")
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
})
@@ -59,7 +62,7 @@ func TestNewRouter(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &Router{
context: ctx,
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: DefaultJSONDocumentationPath,
yamlDocumentationPath: DefaultYAMLDocumentationPath,
@@ -69,7 +72,7 @@ func TestNewRouter(t *testing.T) {
t.Run("ok - with custom docs paths", func(t *testing.T) {
type key struct{}
ctx := context.WithValue(context.Background(), key{}, "value")
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "/json/path",
@@ -79,7 +82,7 @@ func TestNewRouter(t *testing.T) {
require.NoError(t, err)
require.Equal(t, &Router{
context: ctx,
router: mRouter,
router: mAPIRouter,
swaggerSchema: openapi,
jsonDocumentationPath: "/json/path",
yamlDocumentationPath: "/yaml/path",
@@ -89,7 +92,7 @@ func TestNewRouter(t *testing.T) {
t.Run("ko - json documentation path does not start with /", func(t *testing.T) {
type key struct{}
ctx := context.WithValue(context.Background(), key{}, "value")
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "json/path",
@@ -103,7 +106,7 @@ func TestNewRouter(t *testing.T) {
t.Run("ko - yaml documentation path does not start with /", func(t *testing.T) {
type key struct{}
ctx := context.WithValue(context.Background(), key{}, "value")
r, err := NewRouter(mRouter, Options{
r, err := NewRouter(mAPIRouter, Options{
Openapi: openapi,
Context: ctx,
JSONDocumentationPath: "/json/path",
@@ -117,7 +120,7 @@ func TestNewRouter(t *testing.T) {
func TestGenerateValidSwagger(t *testing.T) {
t.Run("not ok - empty swagger info", func(t *testing.T) {
swagger := &openapi3.Swagger{}
swagger := &openapi3.T{}
swagger, err := generateNewValidSwagger(swagger)
require.Nil(t, swagger)
@@ -125,7 +128,7 @@ func TestGenerateValidSwagger(t *testing.T) {
})
t.Run("not ok - empty info title", func(t *testing.T) {
swagger := &openapi3.Swagger{
swagger := &openapi3.T{
Info: &openapi3.Info{},
}
@@ -135,7 +138,7 @@ func TestGenerateValidSwagger(t *testing.T) {
})
t.Run("not ok - empty info version", func(t *testing.T) {
swagger := &openapi3.Swagger{
swagger := &openapi3.T{
Info: &openapi3.Info{
Title: "title",
},
@@ -147,7 +150,7 @@ func TestGenerateValidSwagger(t *testing.T) {
})
t.Run("ok - custom swagger", func(t *testing.T) {
swagger := &openapi3.Swagger{
swagger := &openapi3.T{
Info: &openapi3.Info{},
}
@@ -167,13 +170,13 @@ func TestGenerateValidSwagger(t *testing.T) {
Title: "my title",
Version: "my version",
}
swagger := &openapi3.Swagger{
swagger := &openapi3.T{
Info: info,
}
swagger, err := generateNewValidSwagger(swagger)
require.NoError(t, err)
require.Equal(t, &openapi3.Swagger{
require.Equal(t, &openapi3.T{
OpenAPI: defaultOpenapiVersion,
Info: info,
Paths: openapi3.Paths{},
@@ -184,8 +187,8 @@ func TestGenerateValidSwagger(t *testing.T) {
func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("fails swagger validation", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(mRouter, Options{
Openapi: &openapi3.Swagger{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "title",
Version: "version",
@@ -207,12 +210,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("correctly expose json documentation from loaded swagger file", func(t *testing.T) {
mRouter := mux.NewRouter()
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(mRouter, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: swagger,
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
@@ -233,13 +237,14 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("correctly expose json documentation from loaded swagger file - custom path", func(t *testing.T) {
mRouter := mux.NewRouter()
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(mRouter, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: swagger,
JSONDocumentationPath: "/custom/path",
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
@@ -260,12 +265,13 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("correctly expose yaml documentation from loaded swagger file", func(t *testing.T) {
mRouter := mux.NewRouter()
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(mRouter, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: swagger,
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
@@ -286,13 +292,14 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
t.Run("correctly expose yaml documentation from loaded swagger file - custom path", func(t *testing.T) {
mRouter := mux.NewRouter()
swagger, err := openapi3.NewSwaggerLoader().LoadSwaggerFromFile("testdata/users_employees.json")
swagger, err := openapi3.NewLoader().LoadFromFile("testdata/users_employees.json")
require.NoError(t, err)
router, err := NewRouter(mRouter, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: swagger,
YAMLDocumentationPath: "/custom/path",
})
require.NoError(t, err)
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
@@ -309,4 +316,104 @@ func TestGenerateAndExposeSwagger(t *testing.T) {
require.NoError(t, err)
require.YAMLEq(t, string(expected), body, string(body))
})
t.Run("ok - subrouter", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
Version: "test swagger version",
},
},
JSONDocumentationPath: "/custom/path",
})
require.NoError(t, err)
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
mSubRouter := mRouter.PathPrefix("/prefix").Subrouter()
subrouter, err := router.SubRouter(apirouter.NewGorillaMuxRouter(mSubRouter), SubRouterOptions{
PathPrefix: "/prefix",
})
require.NoError(t, err)
_, err = subrouter.AddRoute(http.MethodGet, "/taz", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
require.NoError(t, err)
t.Run("add route with path equal to prefix path", func(t *testing.T) {
_, err = subrouter.AddRoute(http.MethodGet, "", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
require.NoError(t, err)
})
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
mRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
body := readBody(t, w.Result().Body)
actual, err := ioutil.ReadFile("testdata/subrouter.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
})
t.Run("ok - new router with path prefix", func(t *testing.T) {
mRouter := mux.NewRouter()
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mRouter), Options{
Openapi: &openapi3.T{
Info: &openapi3.Info{
Title: "test swagger title",
Version: "test swagger version",
},
},
JSONDocumentationPath: "/custom/path",
PathPrefix: "/prefix",
})
require.NoError(t, err)
router.AddRoute(http.MethodGet, "/foo", func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}, Definitions{})
err = router.GenerateAndExposeSwagger()
require.NoError(t, err)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/custom/path", nil)
mRouter.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Result().StatusCode)
require.True(t, strings.Contains(w.Result().Header.Get("content-type"), "application/json"))
body := readBody(t, w.Result().Body)
actual, err := ioutil.ReadFile("testdata/router_with_prefix.json")
require.NoError(t, err)
require.JSONEq(t, string(actual), body)
})
}
func readBody(t *testing.T, requestBody io.ReadCloser) string {
t.Helper()
body, err := ioutil.ReadAll(requestBody)
require.NoError(t, err)
return string(body)
}

View File

@@ -3,12 +3,13 @@ package swagger
import (
"errors"
"fmt"
"net/http"
"path"
"sort"
"strings"
"github.com/alecthomas/jsonschema"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/invopop/jsonschema"
)
var (
@@ -22,12 +23,9 @@ var (
ErrQuerystring = errors.New("errors generating querystring schema")
)
// Handler is the http type handler
type Handler func(w http.ResponseWriter, req *http.Request)
// AddRawRoute add route to router with specific method, path and handler. Add the
// router also to the swagger schema, after validating it
func (r Router) AddRawRoute(method string, path string, handler Handler, operation Operation) (*mux.Route, error) {
func (r Router) AddRawRoute(method string, routePath string, handler apirouter.HandlerFunc, operation Operation) (interface{}, error) {
op := operation.Operation
if op != nil {
err := operation.Validate(r.context)
@@ -40,12 +38,11 @@ func (r Router) AddRawRoute(method string, path string, handler Handler, operati
op.Responses = openapi3.NewResponses()
}
}
r.swaggerSchema.AddOperation(path, method, op)
pathWithPrefix := path.Join(r.pathPrefix, routePath)
r.swaggerSchema.AddOperation(pathWithPrefix, method, op)
return r.router.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
handler(w, req)
}).Methods(method), nil
// Handle, when content-type is json, the request/response marshalling? Maybe with a specific option.
return r.router.AddRoute(method, pathWithPrefix, handler), nil
}
// Content is the type of a content.
@@ -58,14 +55,16 @@ type Schema struct {
AllowAdditionalProperties bool
}
// ParameterValue is the struct containing the schema or the content information.
// If content is specified, it takes precedence.
type ParameterValue map[string]struct {
type Parameter struct {
Content Content
Schema *Schema
Description string
}
// ParameterValue is the struct containing the schema or the content information.
// If content is specified, it takes precedence.
type ParameterValue map[string]Parameter
// ContentValue is the struct containing the content information.
type ContentValue struct {
Content Content
@@ -74,6 +73,7 @@ type ContentValue struct {
// Definitions of the route.
type Definitions struct {
Tags []string
PathParams ParameterValue
Querystring ParameterValue
Headers ParameterValue
@@ -90,9 +90,10 @@ const (
)
// AddRoute add a route with json schema inferted by passed schema.
func (r Router) AddRoute(method string, path string, handler Handler, schema Definitions) (*mux.Route, error) {
func (r Router) AddRoute(method string, path string, handler apirouter.HandlerFunc, schema Definitions) (interface{}, error) {
operation := NewOperation()
operation.Responses = make(openapi3.Responses)
operation.Tags = schema.Tags
err := r.resolveRequestBodySchema(schema.RequestBody, operation)
if err != nil {
@@ -104,7 +105,7 @@ func (r Router) AddRoute(method string, path string, handler Handler, schema Def
return nil, fmt.Errorf("%w: %s", ErrResponses, err)
}
err = r.resolveParameterSchema(pathParamsType, schema.PathParams, operation)
err = r.resolveParameterSchema(pathParamsType, getPathParamsAutofilled(schema, path), operation)
if err != nil {
return nil, fmt.Errorf("%w: %s", ErrPathParams, err)
}
@@ -135,10 +136,11 @@ func (r Router) getSchemaFromInterface(v interface{}, allowAdditionalProperties
reflector := &jsonschema.Reflector{
DoNotReference: true,
AllowAdditionalProperties: allowAdditionalProperties,
Anonymous: true,
}
jsonSchema := reflector.Reflect(v)
jsonschema.Version = ""
jsonSchema.Version = ""
// Empty definitions. Definitions are not valid in openapi3, which use components.
// In the future, we could add an option to fill the components in openapi spec.
jsonSchema.Definitions = nil
@@ -258,3 +260,22 @@ func (r Router) addContentToOASSchema(content Content) (openapi3.Content, error)
}
return oasContent, nil
}
func getPathParamsAutofilled(schema Definitions, path string) ParameterValue {
if schema.PathParams == nil {
pathParams := strings.Split(path, "/")
for _, param := range pathParams {
if strings.HasPrefix(param, "{") && strings.HasSuffix(param, "}") {
if schema.PathParams == nil {
schema.PathParams = make(ParameterValue)
}
param = strings.Replace(param, "{", "", 1)
param = strings.Replace(param, "}", "", 1)
schema.PathParams[param] = Parameter{
Schema: &Schema{Value: ""},
}
}
}
}
return schema.PathParams
}

View File

@@ -8,6 +8,7 @@ import (
"net/http/httptest"
"testing"
"github.com/davidebianchi/gswagger/apirouter"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/stretchr/testify/require"
@@ -183,6 +184,24 @@ func TestAddRoutes(t *testing.T) {
testPath: "/users/12",
fixturesPath: "testdata/params.json",
},
{
name: "schema without params autofilled",
routes: func(t *testing.T, router *Router) {
_, err := router.AddRoute(http.MethodGet, "/users/{userId}", okHandler, Definitions{
Querystring: ParameterValue{
"query": {
Schema: &Schema{Value: ""},
},
},
})
require.NoError(t, err)
_, err = router.AddRoute(http.MethodGet, "/cars/{carId}/drivers/{driverId}", okHandler, Definitions{})
require.NoError(t, err)
},
testPath: "/users/12",
fixturesPath: "testdata/params-autofill.json",
},
{
name: "schema with querystring",
routes: func(t *testing.T, router *Router) {
@@ -403,6 +422,17 @@ func TestAddRoutes(t *testing.T) {
testMethod: http.MethodPost,
fixturesPath: "testdata/oneOf.json",
},
{
name: "schema with tags",
routes: func(t *testing.T, router *Router) {
_, err := router.AddRoute(http.MethodGet, "/users", okHandler, Definitions{
Tags: []string{"Tag1", "Tag2"},
})
require.NoError(t, err)
},
testPath: "/users",
fixturesPath: "testdata/tags.json",
},
}
for _, test := range tests {
@@ -410,7 +440,7 @@ func TestAddRoutes(t *testing.T) {
context := context.Background()
r := mux.NewRouter()
router, err := NewRouter(r, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(r), Options{
Context: context,
Openapi: getBaseSwagger(t),
})
@@ -589,8 +619,7 @@ func TestResolveRequestBodySchema(t *testing.T) {
"type":"object",
"properties": {
"id": {"type": "string"}
},
"additionalProperties": true
}
}
}
}
@@ -601,7 +630,7 @@ func TestResolveRequestBodySchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(mux, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)
@@ -744,7 +773,7 @@ func TestResolveResponsesSchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(mux, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)
@@ -914,7 +943,7 @@ func TestResolveParametersSchema(t *testing.T) {
}
mux := mux.NewRouter()
router, err := NewRouter(mux, Options{
router, err := NewRouter(apirouter.NewGorillaMuxRouter(mux), Options{
Openapi: getBaseSwagger(t),
})
require.NoError(t, err)
@@ -936,13 +965,13 @@ func TestResolveParametersSchema(t *testing.T) {
}
}
func getBaseSwagger(t *testing.T) *openapi3.Swagger {
func getBaseSwagger(t *testing.T) *openapi3.T {
t.Helper()
return &openapi3.Swagger{
return &openapi3.T{
Info: &openapi3.Info{
Title: swaggerOpenapiTitle,
Version: swaggerOpenapiVersion,
Title: "test swagger title",
Version: "test swagger version",
},
}
}

View File

@@ -14,13 +14,11 @@
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": true,
"properties": {
"id": {
"type": "string"
},
"address": {
"additionalProperties": true,
"type": "object",
"properties": {
"street": {

1
testdata/oneOf.json vendored
View File

@@ -70,7 +70,6 @@
"type": "string"
},
"metadata": {
"additionalProperties": true,
"oneOf": [
{
"type": "string"

63
testdata/params-autofill.json vendored Normal file
View File

@@ -0,0 +1,63 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/cars/{carId}/drivers/{driverId}": {
"get": {
"parameters": [
{
"in": "path",
"name": "carId",
"required": true,
"schema": {
"type": "string"
}
},
{
"in": "path",
"name": "driverId",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
}
}
}
},
"/users/{userId}": {
"get": {
"parameters": [
{
"in": "path",
"name": "userId",
"required": true,
"schema": {
"type": "string"
}
},
{
"in": "query",
"name": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"default": {
"description": ""
}
}
}
}
}
}

19
testdata/router_with_prefix.json vendored Normal file
View File

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

View File

@@ -32,6 +32,7 @@
}
],
"requestBody": {
"content": {},
"description": "request body without schema"
},
"responses": {

37
testdata/subrouter.json vendored Normal file
View File

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

20
testdata/tags.json vendored Normal file
View File

@@ -0,0 +1,20 @@
{
"components": {},
"info": {
"title": "test swagger title",
"version": "test swagger version"
},
"openapi": "3.0.0",
"paths": {
"/users": {
"get": {
"tags": ["Tag1", "Tag2"],
"responses": {
"default": {
"description": ""
}
}
}
}
}
}