Compare commits

...

360 Commits

Author SHA1 Message Date
Greg Myers
16e40bfcf3
Merge pull request #475 from rswag/fix/workflow
Fix GH Actions being unable to bundle
2022-01-22 22:13:43 +00:00
Greg Myers
8c6aed4a9e
Fix correct gem command
upgrade vs update
2022-01-22 22:12:27 +00:00
Greg Myers
8e59d2b2f2
Fix GH Actions being unable to bundle
Error looks similar to https://github.com/rubygems/rubygems/issues/5150
2022-01-22 22:10:24 +00:00
Greg Myers
a813b63bcc
Merge pull request #450 from marksiemers/master
Loosen gemspec requirement to allow rails 7.0
2021-12-03 22:41:41 +00:00
Greg Myers
076f71388c
Merge pull request #453 from jswk/update-swagger-ui
Update swagger-ui to 3.52.5
2021-12-03 22:39:57 +00:00
Greg Myers
9cfb5bc557
Merge pull request #441 from jaydorsey/jay/better_error_message
Better error message for missing let
2021-12-03 22:39:27 +00:00
Jakub Sawicki
6cafc0c0e5 Update swagger-ui to 3.52.5 2021-10-15 12:06:55 +02:00
Jay Dorsey
86c512f639 Add single quotes around parameter name 2021-09-24 16:11:44 -04:00
Jay Dorsey
32638062d7 Better error message for missing let
I've run into this problem a number of times. The original error message
is actually a `NoMethodError` and it's not always immediately clear what
the solution is, particuarly if you're new to rspec or rswag

Wanted to see if this kind of behavior is something that the rswag team
would be interested in adopting. I have a few other of these in mind
(will do as small PRs, with tests)
2021-09-24 16:10:40 -04:00
Mark Siemers
dd6530b718 Loosen gemspec requirement to allow rails 7.0 2021-09-22 17:32:58 -04:00
Blake Erickson
095906da58
Merge pull request #442 from jaydorsey/jay/mini_racer
Replace therubyracer with mini_racer
2021-08-10 07:12:13 -06:00
Jay Dorsey
a40a06646f Remove therubyracer from contributing 2021-08-08 23:00:40 -04:00
Jay Dorsey
42c8e123a8 Replace therubyracer with mini_racer
therubyracer doesn't appear to be under active development

I didn't need this for PRs that I was doing, but a `bundle install`
failed because of it. I know I can specify the groups as a workaround
but replacing this seems like it might reduce a small barrier to
contributing
2021-08-08 22:40:33 -04:00
Greg Myers
c85fa3b37a
Update README.md 2021-06-16 14:46:04 +01:00
Blake Erickson
985f444834
Merge pull request #426 from smridge/add-reference-to-contributing-doc
Update Contributing Doc with Bundle Install Troubleshooting
2021-05-13 05:09:51 -06:00
Sarah Ridge
1d2a25e231 Update Contributing Doc with Bundle Install Troubleshooting 2021-05-11 09:47:08 -04:00
Blake Erickson
a0680506e2
Merge pull request #416 from mynnx/docs-include-multiple-tags
Document using multiple tags
2021-04-22 17:27:18 -06:00
mynnx
4a32108f78 Document using multiple tags 2021-04-08 15:44:07 -07:00
Blake Erickson
05e22c3bd7
Merge pull request #407 from rswag/revert-300-master
Revert "Add a macro for complexes multiparts"
2021-03-06 14:57:46 -07:00
Blake Erickson
989aab656f
Revert "Add a macro for complexes multiparts" 2021-03-06 14:52:49 -07:00
Blake Erickson
f7036b7e5a
Merge pull request #300 from sobrinho/master
Add a macro for complexes multiparts
2021-03-06 10:22:54 -07:00
Blake Erickson
84ab7a9e4c
Merge pull request #405 from gogainda/master
Add Truffleruby head to CI
2021-03-06 10:01:05 -07:00
Blake Erickson
0169fbab66
Merge pull request #404 from Wolfer/patch-1
Allow use #/components/parameters and other in inherited $refs
2021-03-06 09:58:10 -07:00
Blake Erickson
4c42ad5f97
Merge pull request #406 from mynnx/specs-print-failed-body
Show the response body for comparison when schema checks fail
2021-03-06 09:30:48 -07:00
Blake Erickson
b91b6e5f1e Fix bundler warning
Move rswag-specs under development and test to resolve this warning:

```
Your Gemfile lists the gem rswag-specs (>= 0) more than once.
You should probably keep only one of them.
Remove any duplicate entries and specify the gem only once.
While it's not a problem now, it could cause errors if you change the version of one of them later.
```
2021-03-05 21:34:00 -07:00
mynnx
a34c931bb6 Show the response body for comparison when schema checks fail 2021-03-03 16:32:16 -08:00
Igor Victor
4b7ab9d381
Add Truffleruby head to CI 2021-02-26 17:58:30 +01:00
Serg F
3d3d93f3ab
Allow use #/components/parameters and other in inherited $refs 2021-02-19 15:15:44 +03:00
Blake Erickson
0aca50c66c Update changelog with 2.4.0 info 2021-02-09 11:51:34 -07:00
Blake Erickson
9644a16bce Merge branch 'splitpayments-dry-run-env' 2021-02-09 08:07:35 -07:00
Blake Erickson
52939874d6 Clean up README merge conflict 2021-02-09 08:05:58 -07:00
Blake Erickson
7ef900ec1d version bump 2021-02-07 07:55:52 -07:00
Blake Erickson
c0142093d4 Update swagger-ui to 3.42.0 2021-02-07 07:47:52 -07:00
Blake Erickson
1f4ecb3c10 update changelog 2021-02-07 06:31:47 -07:00
Blake Erickson
aa4e6f2070 Include example definition in test app
From changes in this commit: eadaf34ef6

we need to include the new output in the test-app swagger.json file
2021-02-06 17:42:23 -07:00
Blake Erickson
eadaf34ef6
Merge pull request #394 from donny741/master
Fix response examples
2021-02-06 07:30:53 -07:00
Donatas Povilaitis
cbaf6cd3e4 Fix response examples 2021-01-29 20:47:46 +02:00
Blake Erickson
670c94cc44 Update version to 2.3.2 in changelog 2021-01-27 14:53:15 -07:00
Blake Erickson
b86d3063a8
Merge pull request #371 from rswag/jamie
PR Grooming
2021-01-27 07:59:59 -07:00
Blake Erickson
7f88c5d1f3 Merge branch 'master' into jamie 2021-01-27 05:18:35 -07:00
Blake Erickson
d645df207e
Merge pull request #392 from pfilipow/master
don't clobber response content
2021-01-26 18:10:21 -07:00
Paul Filipow
b63dd343af safe navigation in build_query_string_part 2021-01-26 13:57:44 -08:00
Paul Filipow
bd48e40529 add schema to mime type instead of overwriting 2021-01-25 21:12:16 -08:00
Paul Filipow
465950a65c don't clobber response content 2021-01-25 16:11:54 -08:00
Blake Erickson
be160c5552
Merge pull request #391 from codeart/master
Inherit consumes from swagger schema. Addresses #320.
2021-01-25 14:30:33 -07:00
Alexander
ad95f1098a Inherit consumes from swagger schema. Addresses #320. 2021-01-22 13:25:27 +02:00
Jamie Macey
83567e0ee2
Merge pull request #372 from rswag/spec-deprecations
Clean up spec ouput
2020-10-18 17:59:40 -07:00
Jamie Macey
206c088d74 WIP-branch changelog updates 2020-10-17 14:16:21 -07:00
Jamie Macey
5a60dee838 Add a spec for #342 body/required 2020-10-17 14:15:41 -07:00
Jamie Macey
13a3977c2c Merge remote-tracking branch 'bspellacy/master' into jamie 2020-10-17 13:56:19 -07:00
Jamie Macey
0d1a742f6f empty content is now pruned 2020-10-17 13:44:04 -07:00
Jamie Macey
c62bfda91d Merge branch 'output-specs' into jamie 2020-10-17 13:43:05 -07:00
Jamie Macey
c161de3899 Merge branch 'spec-deprecations' into jamie 2020-10-17 13:43:00 -07:00
Jamie Macey
ab457743a8 also move away from deprecated type: basic 2020-10-17 13:38:56 -07:00
Jamie Macey
3e10b09f23 swap deprecated SecurityDefinitions for SecuritySchemes 2020-10-17 13:38:56 -07:00
Jamie Macey
d090516f48 properly list servers for openapi v3 2020-10-17 13:38:56 -07:00
Jamie Macey
91a27852f2 more flex in this check 2020-10-17 13:38:56 -07:00
Jamie Macey
68e64dba2c OpenAPI currently at v 3.0.3 2020-10-17 13:38:56 -07:00
Jamie Macey
f6630cc7a6 fix a bug related to upgrade_request_type! translation 2020-10-17 13:38:56 -07:00
Jamie Macey
7e1a79220c start standing up exhaustive output unit tests for OpenAPI v3 2020-10-17 13:38:56 -07:00
Jamie Macey
b37c7905cd stub controller to help with future testing 2020-10-17 13:38:56 -07:00
Jamie Macey
0a9487b328 make spec output less noisy 2020-10-17 13:34:17 -07:00
Jamie Macey
b3fa5ba54e Merge remote-tracking branch 'psmandzich/master' into jamie 2020-10-17 13:21:28 -07:00
Jamie Macey
7e2c52b242 Merge remote-tracking branch 'olegkyz/bugfix/examples-content' into jamie 2020-10-17 13:14:47 -07:00
Jamie Macey
8d673068af
Merge pull request #369 from jamie/actions
CI via Github Actions
2020-10-17 08:20:36 -07:00
Greg Myers
d558bd4774
Merge pull request #334 from akofink/issue-333
Update wording in gemspecs to include OpenAPI
2020-10-14 23:08:13 +01:00
Jamie Macey
c990348f0b update cache hash 2020-10-12 13:56:22 -07:00
Jamie Macey
38c861f5e0 strip prelude 2020-10-12 13:51:42 -07:00
Jamie Macey
1cd7df89f1 update conditional tags 2020-10-12 13:48:24 -07:00
Jamie Macey
04059808d5 fix matrix syntax 2020-10-12 13:45:38 -07:00
Jamie Macey
4c06f95a68 run multiple ruby/rails versions 2020-10-12 13:43:58 -07:00
Jamie Macey
08b1678e53 skip a test requiring headless firefox capybara driver 2020-10-12 13:37:57 -07:00
Jamie Macey
27b015b3d2 ensure we run all specs if there are early failures 2020-10-12 13:29:28 -07:00
Jamie Macey
eb14eba7eb build individually 2020-10-12 13:26:31 -07:00
Jamie Macey
e419635209 cache gems/npm 2020-10-12 13:20:46 -07:00
Jamie Macey
ea89b0b0d5
Github Actions CI 2020-10-12 13:16:17 -07:00
Jamie Macey
423e86c463 bump ruby-version, stricter npm lockfile 2020-10-12 13:13:53 -07:00
Greg Myers
89f95694a4
Merge pull request #349 from MikeSmithEU/patch-1
Fix typo in test-app/app/controllers/blogs_controller.rb
2020-08-21 17:08:13 +01:00
Greg Myers
6133179aa5
Merge pull request #312 from levidavidmurray/master
Update README.md
2020-08-21 17:07:12 +01:00
Greg Myers
89e69915f8
Merge pull request #335 from zkatemor/master
Update version Swagger UI to 3.28.0
2020-08-17 15:04:31 +01:00
Greg Myers
4e300b2255
Update changelog, readme
Swagger-ui version no.
2020-08-17 15:04:22 +01:00
Greg Myers
3cb3f4a651
Merge pull request #324 from graceful-potato/fix_route_parser
Fix routes method in RoutePareser
2020-08-17 15:03:00 +01:00
MikeSmithEU
267007ef1b
Update blogs_controller.rb
Fix typo
2020-07-22 11:23:01 +02:00
psmandzich
347f9da32e enable swagger empty body responses 2020-07-21 09:50:47 +02:00
Brennan Spellacy
30002e5b98 Add required field 2020-07-01 20:20:41 -07:00
Ekaterina Zababurina
a7944d48d6 Update Swagger UI to 3.28.0 2020-06-30 09:45:55 +03:00
Ekaterina Zababurina
015b1c8b56 Update Swagger UI to 3.27.0 2020-06-25 13:37:23 +03:00
Ekaterina Zababurina
36e79da0fd Update swagger UI to 3.26.2 2020-06-16 10:15:35 +03:00
Ekaterina Zababurina
3aff6bca1f Update version Swagger UI to 3.26.0 2020-06-10 09:19:57 +03:00
Andrew Kofink
f0fba9c093
Update wording in gemspecs to include OpenAPI
Fixes #333

Mentioning OpenAPI in the gemspec allows users on rubygems.org to find
this gem easily. Those who are still looking for Swagger tools will also
continue to find the gem, since I've mentioned that OpenAPI used to be
called Swagger.

Signed-off-by: Andrew Kofink <akofink@redhat.com>
2020-06-08 12:00:08 -04:00
Greg Myers
bec4f16676
fix #322 2020-06-06 19:56:28 +01:00
Oleg Yakovenko
7c3c357291 cleanup 2020-06-04 17:22:20 +03:00
Oleg Yakovenko
81c110022e example json actualized 2020-06-04 17:19:15 +03:00
Oleg Yakovenko
1ff396fb56 example group helper adjustment 2020-06-04 17:17:30 +03:00
Oleg Yakovenko
9c297317b2 keep examples content 2020-06-04 16:21:43 +03:00
Graceful Potato
3b85f09acf Fix RoutePareser#routes and add spec for it 2020-05-26 02:01:38 +03:00
Levi Murray
9727ec34b7 Update README.md 2020-05-03 13:58:04 -07:00
Gabriel Sobrinho
f8dbd98bbc
Add a macro for complexes multiparts
This will allow to describe multipart in a short way, like JSON payload:

Before:

    put 'Creates a blog with thumbnail' do
      consumes 'multipart/form-data'
      parameter name: :title, in: :formData, type: :string, required: true
      parameter name: :content, in: :formData, type: :string, required: true
      parameter name: :file, in: :formData, type: :file, required: true

      let(:blog) { FactoryBot.build(:blog) }
      let(:title) { blog.title }
      let(:content) { blog.content }
      let(:file) { blog.file }

      ...
    end

After:

    put 'Creates a blog with thumbnail' do
      consumes 'multipart/form-data'
      parameter name: :blog, in: :formData, schema: { '$ref' => '#/definitions/blog' }

      let(:blog) { FactoryBot.attributes_for(:blog) }

      ...
    end

Your mileage may vary but you can always choose the best option.
2020-04-16 22:38:35 -03:00
Greg Myers
7ceedab4cb
Update CHANGELOG.md 2020-04-08 23:12:33 +01:00
Greg Myers
e7fb44fcf5
Merge pull request #296 from rswag/BookOfGreg-patch-1
fix #295
2020-04-08 23:10:55 +01:00
Greg Myers
2797866224
fix #295 2020-04-08 23:09:31 +01:00
Greg Myers
4de6661f4c
Update README.md 2020-04-08 23:08:46 +01:00
Greg Myers
42fdf6d482
Merge pull request #286 from BookOfGreg/openapi/merge
Support for some openapi3 features
2020-04-05 01:05:17 +01:00
Greg Myers
24a1483929 update changelog 2020-04-05 01:02:46 +01:00
Greg Myers
4ab432080b update Readme 2020-04-05 00:53:04 +01:00
Greg Myers
a96a466205 doctoc the readme 2020-04-05 00:44:20 +01:00
Greg Myers
965f14406f add support for oneOf anyOf allOf 2020-04-05 00:36:25 +01:00
Greg Myers
d644a91da5 Remove all commented code. Add "nullable" 2020-04-04 23:37:38 +01:00
Greg Myers
b158f1e164 add specific test for formData 2020-04-04 23:05:26 +01:00
Greg Myers
e53f2ca257 remove commented code. 2020-04-04 23:02:25 +01:00
Greg Myers
2af7c13e59 feature handle in: :body and :formData params 2020-04-04 22:53:23 +01:00
Greg Myers
cbc7a33ac3 feature remove trailing produces and consumes 2020-04-04 21:25:17 +01:00
Greg Myers
f1f8b0ed18 fix oauth corrections correct way round 2020-04-04 21:03:04 +01:00
Greg Myers
96fc5276c4 add oauth flow renaming and warnings 2020-04-04 20:55:04 +01:00
Greg Myers
d66be41d04 Fix oauth2 transform keys except type 2020-04-04 20:43:31 +01:00
Greg Myers
bd038949b4 Fix incorrect merge, Capybara::Webkit no longer loaded 2020-04-04 20:09:21 +01:00
Greg Myers
74ea37e048
Merge branch 'master' into openapi/merge 2020-04-04 20:05:00 +01:00
Greg Myers
d32f098e0b
Merge pull request #187 from pjdavis/configure-response-header-in-rswag-api
allow headers to be set in the configuration of rswag-api
2020-04-04 20:01:04 +01:00
Greg Myers
1996f5130f
doc: note that content-type is dynamic 2020-04-04 20:00:39 +01:00
Greg Myers
8ae6653cf7
Merge branch 'master' into configure-response-header-in-rswag-api 2020-04-04 19:57:16 +01:00
Greg Myers
05dfd08f15
Merge pull request #239 from hdpuk86/master
update swagger-ui to 3.23.11
2020-04-04 19:53:18 +01:00
Greg Myers
e0ed6bb646
Merge branch 'master' into openapi/merge 2020-04-04 19:47:12 +01:00
Greg Myers
5e2663eb6a
Merge pull request #293 from BookOfGreg/extend-output
add output for swaggerize command by inheriting thhe base text formatter
2020-04-04 19:46:37 +01:00
Greg Myers
bd06ebe526
Merge pull request #167 from akabiru/feat/add-basic-auth
🔒Add Optional Basic Auth for Rswag UI
2020-04-04 18:29:39 +01:00
Greg Myers
b000c94ea0 add output for swaggerize command by inheriting thhe base text formatter 2020-03-29 20:27:36 +01:00
Greg Myers
02cf2e668b doc update message about metadata[:operation] 2020-03-29 20:25:27 +01:00
Greg Myers
1f745003ff fix do not delete from operation level metadata 2020-03-29 20:16:03 +01:00
Greg Myers
cddb7ae614
add preamble to contributing guide
we wish to make it easier to know what to expect as a contributor.
That is we want semantic versioning, and we want you to know that contributions are valuable, and that as a contributor you don't own anyone anything so there's no pressure.
2020-03-27 00:16:07 +00:00
Greg Myers
405ccca494 Add upgrades for consumes and produces in content with schemas 2020-03-26 23:37:00 +00:00
Greg Myers
c739228c89 ignore byebugs anywhere 2020-03-26 23:36:12 +00:00
Greg Myers
3393263df7 Remove duplicate test block 2020-03-26 22:17:16 +00:00
Igor Kapkov
9916d3f0b0
Merge branch 'master' into dry-run-env 2020-03-25 16:59:30 +11:00
Igor Kapkov
56eec5948e Update readme 2020-03-25 16:57:58 +11:00
Greg Myers
6b4f49aacb Basic rubocops 2020-03-24 16:02:13 +00:00
Greg Myers
5060697761 add conversion oauth flow to flows 2020-03-24 15:20:15 +00:00
Greg Myers
231a2d135c add rewrite for securitySchemes into swagger_doc 2020-03-24 14:56:24 +00:00
Greg Myers
b70e3a0794
Merge pull request #289 from bjelline/patch-1
fix README.md: dry_run goes into test.rb, not application.rb
2020-03-23 15:14:18 +00:00
Brigitte Jellinek
3046ea9f33
fix README.md: dry_run goes into test.rb, not application.rb
adding RSpec.configure to application.rb can lead to problems in production, where rspec may not be present.
config/environments/test.rb avoids these problems.
2020-03-23 07:10:23 +01:00
Greg Myers
e9aebe6221 fix mistake in assigning header nodes for type 2020-03-22 23:45:47 +00:00
Greg Myers
eb58fe687a add upgrade for basepath and host to server urls 2020-03-22 23:39:48 +00:00
Greg Myers
da230a4f3e add header type schema support for openapi3 2020-03-21 23:17:00 +00:00
Greg Myers
a25307dc69 add support for openapi 3 securitySchemas 2020-03-21 23:14:58 +00:00
Greg Myers
9414ca16b6 add upgrade parameters refs to openapi3 2020-03-21 22:38:49 +00:00
Greg Myers
70eb277e04 add upgrade path and query param type output to openapi3 if selected 2020-03-21 21:38:09 +00:00
Greg Myers
23a1074d07 Add tests for OA3 components/schemas loader with upgrade notice 2020-03-21 20:24:04 +00:00
Greg Myers
095067792f add loader for OA3 schema definitions with version based deprecation
notice
2020-03-21 19:51:01 +00:00
Greg Myers
2b239ef0f3 Reverted some files related to definitions changes 2020-03-21 17:04:41 +00:00
Greg Myers
0020d71c90 Remove deprecation warnings for Rails 5 and 6 2020-03-20 20:52:36 +00:00
Greg Myers
b5e210cd96 Merge branch 'openapi/master' into openapi/merge 2020-03-20 15:38:40 +00:00
Kabiru Mwenja
333a0b535a
Merge pull request #1 from PSPinc/feat/add-basic-auth
fix(references): update reference to Rswag::Ui::BasicAuth and env_mat…
2020-01-30 10:18:58 +03:00
Chris Miller
e21f786926 fix(references): update reference to Rswag::Ui::BasicAuth and env_matching_path environment accessor 2020-01-29 16:28:06 -08:00
Rutger Gelling
f331e064fd Add yaml support (#7) 2020-01-27 20:24:27 -05:00
Rutger Gelling
79304a1bc1 Add support for multiple content types in examples (#8) 2020-01-27 20:20:36 -05:00
Rutger Gelling
b9ac008a9f Point to the correct version of rswag-specs (#6) 2020-01-27 20:20:07 -05:00
Igor Kapkov
7b01ae1aa1 Add ENV var to configure --dry-run 2020-01-22 15:54:24 +11:00
Kabiru Mwenja
a43e6f6546
fix(rswag-ui): Define BasicAuth in Rswag::Ui module 2020-01-06 10:55:43 +03:00
Kabiru Mwenja
6e706c04d7
Merge branch 'origin/master' into feat/add-basic-auth 2020-01-06 10:01:19 +03:00
Kabiru Mwenja
19e985a828
chore(rswag-ui): Organise basic auth files 2020-01-06 09:50:30 +03:00
Greg Myers
63f01962ad
Merge pull request #254 from fooki/master
Parameterize the pattern for test locations
2019-11-17 09:55:54 +00:00
Greg Myers
e6bfba23d7
Merge pull request #255 from fooki/skip-documentation
Allow tests to be run without generating docs
2019-11-17 09:53:45 +00:00
Karl Johansson
4c613af2ba Allow tests to be run without generating docs
By providing the 'document: false' metadata, tests will be run but no swagger
documentation will be generated for the tagged example groups. It works on all
kinds of example groups (responses, verbs, paths etc..).
2019-11-15 16:21:04 +01:00
Karl Johansson
3cd9d38e19 Parameterize the pattern for test locations
This commit allows users to specify search patterns when finding tests to
swaggerize. Omitting the pattern parameter makes rswag search with the default
patterns.

A typical usecase for this feature is when you already have a test suite set up
and you want to use rswag for generating swagger docs rather than high-coverage
testing.

Usage:

rake rswag:specs:swaggerize PATTERN='/your_path..'
2019-11-15 14:51:17 +01:00
Greg Myers
02a5bc988f
Merge pull request #253 from BookOfGreg/rails-7-constraint
Move constraint to less than rails 7
2019-11-02 17:09:24 +00:00
Greg Myers
c904a32e51 Move constraint to less than rails 7 2019-11-02 17:06:21 +00:00
Greg Myers
a46a5be3bb Use presence on tags in travis 2019-11-02 16:55:21 +00:00
Greg Myers
ccce4d6360 Fix travis.yml 2019-11-02 16:11:42 +00:00
Greg Myers
663294b84b
Merge pull request #251 from BookOfGreg/improved-yaml-support
Improved yaml support
2019-11-02 16:09:50 +00:00
Greg Myers
889dd0922a Merge branch 'master' into improved-yaml-support 2019-11-02 16:03:11 +00:00
Greg Myers
99281f96be
Merge pull request #252 from BookOfGreg/speedup-travis
Use a prebuilt ruby
2019-11-02 16:02:51 +00:00
Greg Myers
3dc0909a6a Use specific directory. We dont bundle to vendor/bundle 2019-11-02 15:59:48 +00:00
Greg Myers
dad99930aa trigger build 2019-11-02 15:56:08 +00:00
Greg Myers
c108a8367c try conditional stages 2019-11-02 15:48:29 +00:00
Greg Myers
8d8fc11e55 correct ruby-version for travis 2019-11-02 15:35:51 +00:00
Greg Myers
8d04646341 Cache the correct directory 2019-11-02 15:09:21 +00:00
Greg Myers
f8fb73fb14 Use a prebuilt ruby
https://docs.travis-ci.com/user/reference/bionic/
Pre-installed Rubies: 2.3.8, 2.4.5, 2.5.3 and 2.6.3.
2019-11-02 15:03:45 +00:00
Greg Myers
4516ad4b78 Update changelog and tweak readme 2019-11-02 14:52:37 +00:00
Greg Myers
2d5da62bf1 CHANGELOG.md 2019-11-02 14:02:31 +00:00
Greg Myers
dc161fe275 Serve yaml files as yaml instead of converting them to json 2019-11-02 13:57:47 +00:00
Greg Myers
eeb1026691 Fix invalid Swagger in YAML values
The original fix failed because though the Keys were now strings, some
of the values for path variables were also symbols.
Psych does have a safe_load which has a whitelist of classes but it does
not have a safe_dump mode. We could have used deep_transform_values and
manually converted the classes we did not want, but why risk a buggy
implementation when JSON.generate works just fine?
2019-11-02 13:13:06 +00:00
Greg Myers
2c0f3c9396 Fix invalid Swagger in YAML 2019-11-02 12:58:36 +00:00
Greg Myers
acab437a7d Add failing test showing Psych errors 2019-11-02 12:55:09 +00:00
Greg Myers
3ff1de5d65 Update changelog 2019-11-02 11:40:07 +00:00
Greg Myers
0e04635b15 Write the files using specified format 2019-11-02 11:19:01 +00:00
Greg Myers
73b84101cc Adding yaml as option for generator
New installations will get :yaml as it's default with openapi 3 as the
version. Old installations will have the key missing and will default
to :json with an easy upgrade path.
2019-11-02 10:45:38 +00:00
Hayley Prior
9cbd85a22a
Delete yarn.lock 2019-10-24 22:06:26 +01:00
Hayley Prior
ef78b0c98f
Delete .yarn-integrity 2019-10-24 22:06:00 +01:00
Hayley Prior
354208ac03
Merge pull request #3 from hdpuk86/fix/swagger-ui-update
update swagger-ui to 3.23.11
2019-10-24 21:55:08 +01:00
hdpuk86
b29373c0c4 update swagger-ui to 3.23.11 2019-10-24 21:53:48 +01:00
Hayley Prior
2e9015dd12
Merge pull request #2 from hdpuk86/merge-master-fork
Merge master fork
2019-10-24 21:34:04 +01:00
hdpuk86
db45cafea2 merge master fork 2019-10-24 21:17:23 +01:00
Greg Myers
2cf6812ae0
Update README.md 2019-10-19 21:39:24 +01:00
Greg Myers
90d7fada85
Merge pull request #249 from BookOfGreg/fix/swagger-generator
Point the railtie to the correct file
2019-10-18 23:28:43 +01:00
Greg Myers
c14f72a45e Point the railtie to the correct file
Fixes #248
2019-10-18 23:18:32 +01:00
Greg Myers
9722419647
Merge pull request #180 from fishpercolator/default_swaggerize
Add a 'rake rswag' that runs swaggerize as the default
2019-10-17 22:35:50 +01:00
Greg Myers
bf6bd59094
Merge pull request #247 from laurawatson/swaggerize-task
Update README
2019-10-17 18:28:37 +01:00
Laura Watson
ea2ed6ca49 Update README 2019-10-17 17:18:27 +01:00
Greg Myers
d12c018cb7
Merge pull request #246 from laurawatson/pr-template
PR & Issue templates
2019-10-17 16:54:22 +01:00
Greg Myers
d84a89510d
Merge pull request #190 from bclewis1/allow-yaml-parsing-in-rswag-api
Allow parsing of yml swagger files in rswag-api
2019-10-17 16:53:11 +01:00
Laura Watson
8d7385fcac update copy 2019-10-17 16:22:12 +01:00
Laura Watson
a18d9e5163 update copy 2019-10-17 14:36:25 +01:00
Laura Watson
5b1dde772a Update pr template 2019-10-17 14:27:07 +01:00
Laura Watson
29becf98f8 add issue templates 2019-10-17 14:16:46 +01:00
Laura Watson
1d5ed8345f add a PR template 2019-10-17 13:37:36 +01:00
Laura Watson
71423cffb6 Merge branch 'master' of github.com:rswag/rswag 2019-10-17 13:34:54 +01:00
Greg Myers
0def9fad6f
Merge pull request #152 from DocSpring/fix_irb_context_warning
Call disable_monkey_patching! for RSpec configuration, to fix IRB context warning in Rails console
2019-10-17 10:47:59 +01:00
Nathan Broadbent
e5eb44191c Use RSpec.describe to fix IRB context warning in Rails console 2019-10-17 16:40:31 +07:00
Greg Myers
28245d4dd0
Update README.md 2019-10-17 10:02:24 +01:00
Greg Myers
07c4c74d75 Update changelog 2019-10-17 00:02:09 +01:00
Greg Myers
b1e089af6a
Merge pull request #204 from stefanosx/patch-1
Update README.md
2019-10-16 23:45:53 +01:00
Greg Myers
47eb1e49ee
Merge pull request #245 from BookOfGreg/feature/spec_generator
Feature/spec generator
2019-10-16 23:30:08 +01:00
Greg Myers
4d29e09010 Add spec generator test 2019-10-16 23:19:24 +01:00
Greg Myers
189a7ef061 Move spec generator files, organize whitespace in generator output 2019-10-16 22:05:14 +01:00
Greg Myers
5ee880b769 Merge branch 'feature/request_spec_generator' 2019-10-16 21:12:51 +01:00
Greg Myers
778d250385 Split file join path 2019-10-16 21:12:36 +01:00
Greg Myers
dd2eaf2feb
Merge pull request #75 from paulccarey/feature/request_spec_generator
adds request spec generator (shamelessly stollen from rspec-rails-swagger)
2019-10-16 21:11:20 +01:00
Greg Myers
77d00407a4 whitespace linting 2019-10-16 20:51:53 +01:00
Greg Myers
8b61984fb3
Merge branch 'master' into feature/request_spec_generator 2019-10-16 20:44:11 +01:00
Greg Myers
3542cd0857 Add a Sprockets 4 manifest
Fix #243
2019-10-14 22:17:12 +01:00
Greg Myers
69edcd1be6
Merge branch 'master' into allow-yaml-parsing-in-rswag-api 2019-10-14 21:41:18 +01:00
Greg Myers
b41d4e1276
Merge pull request #240 from hdpuk86/update-swagger-ui-to-3.18.2
update swagger ui to 3.18.2
2019-10-08 23:54:14 +01:00
Hayley
d01dff199c potential test fix 2019-10-08 16:43:11 +01:00
Hayley
dc2ebd94bb update swagger ui to 3.18.2 2019-10-08 16:18:55 +01:00
Hayley Prior
ca8a2b6da2
Merge pull request #1 from BookOfGreg/h-master
Replace webdriver with firefox-headless
2019-10-08 15:59:33 +01:00
Greg Myers
ac1d61b08f Replace webdriver with firefox-headless 2019-10-08 15:57:16 +01:00
Hayley
2c3c23e460 update changelog.md and contributing.md 2019-10-07 17:23:25 +01:00
Hayley
90df5bfa30 update package-lock 2019-10-07 17:11:16 +01:00
Hayley
bff44ee06e update swagger-ui to 3.23.11 2019-10-07 16:55:20 +01:00
Greg Myers
17d7e020e8
Merge pull request #237 from PMGH/master
Add options and trace verbs
2019-10-05 20:35:48 +01:00
Laura Watson
57da84d055 add options and trace 2019-10-04 14:52:47 +01:00
Peter McCready
5c9154864e add options and trace verbs 2019-10-04 14:51:41 +01:00
Greg Myers
0246ff164f Update readme 2019-10-03 23:00:27 +01:00
Greg Myers
f4ba3266ba
Merge pull request #235 from BookOfGreg/doc/update-contrib
Update contributing instructions. Add changelog
2019-10-03 22:46:41 +01:00
Greg Myers
a3aa56e2df Add a message on how to release to contributing guide 2019-10-03 22:37:48 +01:00
Greg Myers
3329c1ec55 Add Changelog
Fix #38
2019-10-02 14:10:18 +01:00
Greg Myers
8bdf3eac08 Update the contributing doc, referencing the CI files 2019-10-02 13:50:56 +01:00
Greg Myers
ed25ff36e6
Merge pull request #210 from olleolleolle/patch-1
CONTRIBUTING: Correct URL
2019-09-30 21:54:54 +01:00
Greg Myers
7df00dde94
Merge pull request #227 from biow0lf/biow0lf-patch-1
Fix typo
2019-09-30 21:12:11 +01:00
Greg Myers
2a8c0cee4b
Merge pull request #234 from rswag/BookOfGreg-patch-1
Update README.md
2019-09-30 21:09:23 +01:00
Greg Myers
e03af84262
Merge pull request #228 from thiagopradi/rails-6-full-support
Rails 6 Support
2019-09-30 21:09:04 +01:00
Greg Myers
b7a6b2de8b
Update README.md
Repoint readme links
2019-09-30 21:06:14 +01:00
Thiago Pradi
4bdbd7ed98 Use updated ruby on CI too 2019-09-23 23:03:09 -03:00
Thiago Pradi
6c684729d1 Use updated ruby version 2019-09-23 22:56:24 -03:00
jdanielian
72becffefe
Merge pull request #5 from gravityslave92/master
Remove hindrance for migrating to rails 6
2019-09-07 08:33:01 -04:00
Jay Danielian
6a4cc8de8d Adds fix for multiple files to be marked in request_body_multipart 2019-09-07 08:21:56 -04:00
gravityslave92
5fe1637407
update dependency add protection 2019-09-06 14:59:25 +03:00
gravityslave92
275c3b1994
Update dependency add versional protection 2019-09-06 14:58:00 +03:00
gravityslave92
3da9eda063
Update dependency add protecting check 2019-09-06 14:57:22 +03:00
gravityslave92
8f2378eb6f Remove hinders for migrating to rails 6 2019-09-06 12:57:44 +03:00
jdanielian
6467ce6543
Merge pull request #4 from jdanielian/response-example
Only automatically save examples if examples are not given explicitly…
2019-08-26 23:08:44 -04:00
Jay Danielian
4670dcd4b0 Removes rails 4.2.8 due to bundler conflicts 2019-08-26 23:01:38 -04:00
Jay Danielian
91ae7732c2 Adding services startup for travis 2019-08-26 22:57:05 -04:00
Jay Danielian
90af919af3 Removes startup script trying to get travis build to work 2019-08-26 22:46:30 -04:00
Jay Danielian
02f72a4b1a Trying to fix capybara 2019-08-26 22:39:13 -04:00
Jay Danielian
5555edc59f Only automatically save examples if examples are not given explicitly in the spec itself 2019-08-26 22:25:53 -04:00
Thiago Pradi
81f8e0dbaf Removing Rails 3/4 - they are not supported by the Rails Core Team 2019-08-25 23:19:03 -03:00
Thiago Pradi
91a0f88eb5 Use different Sqlite versions for Rails versions 2019-08-25 23:11:57 -03:00
Thiago Pradi
586d0211ff Force SQlite 1.3 version 2019-08-25 23:06:19 -03:00
Thiago Pradi
d379338017 Enforce SQlite version 2019-08-25 23:00:07 -03:00
Thiago Pradi
7179802fe0 Using alternative config for xfvb 2019-08-25 22:50:28 -03:00
Thiago Pradi
16458d458a Adding extra lib to fix build 2019-08-25 22:45:12 -03:00
Thiago Pradi
621d6f4754 Updating travis file and adding Rails 6 to build matrix 2019-08-25 22:37:22 -03:00
Thiago Pradi
ac65dc1780 Gemfile / gemspec files compatible with Rails 6 2019-08-25 22:36:14 -03:00
Igor Zubkov
a00145c1f7
Fix typo 2019-08-20 16:51:27 +03:00
Jay Danielian
ce8237110f Updates travis script 2019-08-04 11:51:17 -04:00
Jay Danielian
5e48a2cae3 fixes badge path 2019-08-04 11:23:45 -04:00
jdanielian
9ba484dc37
Merge pull request #3 from jdanielian/documentation
Updates README with proper links and examples
2019-08-04 11:13:31 -04:00
Jay Danielian
5a8d1ce359 Updates README with proper links and examples for new OpenApi 3.0 syntax / features
Missed a few generator items as part of the rename
2019-08-04 11:00:33 -04:00
Jay Danielian
9bc6e2e16a Adds 4.2.8 to minimum rails version, as rails 4.2.0 was erroring out on certain ::Numeric extensions 2019-08-01 14:19:11 -04:00
jdanielian
04298d655b
Merge pull request #2 from jdanielian/travis-ci
Finishes some renaming elements that were missed previously
2019-08-01 14:09:24 -04:00
Jay Danielian
157175c90f Finishes some renaming elements that were missed previously
Modifes the travis.yml in trying to setup travis CI build
2019-08-01 14:05:57 -04:00
Jay Danielian
6d285d2c4f Notes in the todos 2019-08-01 13:05:44 -04:00
jdanielian
c889e407ec
Merge pull request #1 from jdanielian/open-api-rename
Open api rename
2019-08-01 09:15:52 -04:00
Jay Danielian
032ad5dc54 Fixes last little pathing mistakes from rename
All specs are passing in all gems and in test-app

Properly generates open api 3 swagger via rake rswag:specs:swaggerize and via bundle exec rspec in test-app dir
2019-08-01 09:10:38 -04:00
Jay Danielian
475929e9aa Renames gems to open_api-rswag-* 2019-08-01 08:37:05 -04:00
Jay Danielian
13f7007b2f Renames and fixes specs in api and specs project to prefix OpenApi module. Gem name to open_api-rswag 2019-07-27 14:53:01 -04:00
Jay Danielian
db3f321b45 References newly named open_api-rswag-api gem 2019-07-23 22:24:23 -04:00
Jay Danielian
27a7481b48 Renames rswag-api to open_api-rswag-api 2019-07-23 22:23:59 -04:00
Jay Danielian
b8dcc8fe30 Adds support for proper requestBody examples. Adds mechanism to allow for adding additional ways to add request body examples
Can add externalValue or  it will work and produce valid swagger spec.

The Symbol name matching the let parameter is always required
2019-07-21 15:03:37 -04:00
Jay Danielian
4c2097e017 Fixes response_validator to handle 3.0 responses and validate against the schema.
JSON::Validator already handles anyOf oneOf schema definitions, so those can be passed in and validation errors are returned properly
2019-07-20 14:33:51 -04:00
Jay Danielian
cd348b53f8 Adds anyOf support to requestBody 2019-07-20 13:50:38 -04:00
Jay Danielian
eb4e6045c5 Modifies generator and specs to look for openapi: 3.0.0 vs swagger 2.0
Renames rswag-api to rswag_api as that is preferred file naming convention in initializers per rubocop linting
2019-07-20 12:52:31 -04:00
Jay Danielian
4baf5efd11 Updates specs to add 3.0 compliant structure and tests around the new schema/structure 2019-07-20 12:29:44 -04:00
Jay Danielian
04564d933f Fixes example group helpers spec with new 3.0 format 2019-07-18 22:19:10 -04:00
Jay Danielian
aa59c5ff91 Fixes response validators specs for v3 structure 2019-07-18 22:01:00 -04:00
Jay Danielian
659b328eda Fixes spec for #stop writing swagger docs 2019-07-17 20:35:56 -04:00
Jay Danielian
5e71651d6d Adds auth_tests_spec and validated that it is generating valid 3.0 security related swagger 2019-07-17 20:18:12 -04:00
Jay Danielian
28bcc121ba formatting 2019-07-17 20:10:10 -04:00
Jay Danielian
aa133b90fc Adds request_body_multipart method which enables schema properties to be written for multipart upload body
Will inspect the provided hash and add the property file_name to the parameters collection so upload and 3.0 output will work properly
2019-07-17 20:07:30 -04:00
Jay Danielian
c820bb75e0 Modifies parameters and body request/responses to output 3.0 syntax for basic operations.
SwaggerEditor passes basic output
2019-07-14 17:28:11 -04:00
Jay Danielian
23349b2678 Adds byebug_history file in gitignore 2019-07-14 14:26:50 -04:00
Jay Danielian
fd061a2a7f Removes byebug history 2019-07-14 14:26:16 -04:00
Jay Danielian
0093efd4bf Adds rswag to test and development so rake tasks work
Adds to swagger_Formatter to remove injected body parameters since those are 2.0 and ont 3.0 compliant

Adds to example_group_helpers to only automatically save request examples in the swagger output on 2xx response, since otherwise it was getting clobbered
2019-07-07 22:57:55 -04:00
Jay Danielian
297cc447c8 Gets v3 request example saving as well as response example saving
Adds rubocop to the gemset

adds guard to the gemset for testing
2019-07-05 15:59:47 -04:00
Jay Danielian
5d7fc44af4 Updates docs to include setting up rswag-ui assets first time locally 2019-06-30 13:06:12 -04:00
Jay Danielian
768a1a1d43 Initial commit for trying to produce and consume v3 swagger 2019-06-29 18:12:21 -04:00
Olle Jonsson
f969fb6573
CONTRIBUTING: Correct URL 2019-04-17 14:46:26 +02:00
Richard Morris
10bb732148
Merge pull request #177 from FormAPI/show_response_body_for_invalid_code
Show response body when the response code is unexpected.
2019-04-08 12:25:28 +01:00
Richard Morris
c74c88fd46
Merge pull request #176 from BookOfGreg/patch-1
Update swagger_helper.rb
2019-04-08 12:24:54 +01:00
Richard Morris
9cb187192d
Merge pull request #23 from drewish/contributing
Add a contributing file
2019-04-08 12:17:32 +01:00
Richard Morris
636cdcd8b3
Merge pull request #92 from seriousbee/add-section-on-formatting-to-RM
Updated Readme.md:
2019-04-08 12:17:05 +01:00
stefanosx
49b5059273
Update README.md
You need to run the generation of rswag:api:install rswag:ui:install in separated lines to work
2019-03-06 12:59:24 +01:00
Ben Lewis
9eb2d3ddec Allow ".yaml" and ".yml" filename endings for yaml 2019-02-12 10:47:15 +00:00
Ben Lewis
51b47f32e8 version compatibility 2019-02-06 12:15:01 +00:00
Ben Lewis
29c9f7cae2 Allow parsing of yml swagger files in rswag-api 2019-02-06 11:43:02 +00:00
PJ Davis
d00bb06e19 allow headers to be set in the configuration of rswag-api 2019-01-30 13:46:13 -05:00
Rich Daley
bfd3d66ec2 Add a 'rake rswag' that runs swaggerize as the default 2019-01-07 14:17:53 +00:00
Nathan Broadbent
e381bf85d4 Show response body when the response code is unexpected. Makes it much easier to debug test failures 2018-12-22 15:20:49 +07:00
Greg Myers
9642937ee2
Update swagger_helper.rb
Use standard filesystem helpers to avoid OS specific slash errors.
2018-12-18 13:29:40 +00:00
Austin Kabiru
529cfae73e
fix: Scope auth to swagger endpoints 2018-12-03 11:26:01 +03:00
Austin Kabiru
875bbfa04b
chore(auth): Add documentation and specs 2018-11-30 14:54:10 +03:00
Austin Kabiru
b0712418a3
feat(auth): Allow Basic auth to be enabled 2018-11-30 12:33:13 +03:00
Richard Morris
a50bf616b9
Merge pull request #156 from earksiinni/patch-1
Fix installation instructions for separate gems
2018-10-09 15:02:44 -07:00
Ersin Akinci
d69aa16985
Fix installation instructions for separate gems 2018-10-09 13:44:58 -07:00
Richard Morris
4d1f5f831b
Merge pull request #150 from MSanteler/master
Update comment in swagger_helper template
2018-09-19 16:24:18 -07:00
Matthew Santeler
aa8f16070d Update comment in swagger_helper template 2018-09-19 15:24:16 -04:00
Richard Morris
6fc9faab57
Reflect swagger-ui upgrade in readme 2018-07-11 09:01:50 -07:00
Richard Morris
5ea1670d79
Merge pull request #136 from ledermann/upgrade-swagger-ui-to-3-17-3
Upgrade Swagger UI to 3.17.3
2018-07-10 07:53:01 -07:00
Georg Ledermann
00aa08bb22 ⬆️ Upgrade "swagger-ui" to 3.17.3 2018-07-10 14:49:12 +02:00
Richard Morris
ef91e087d3 Update compatibility chart to reflect realty 2018-06-21 23:27:57 -07:00
Richard Morris
be6def33ac
Merge pull request #134 from ledermann/upgrade-swagger-ui-to-3-17-1
Upgrade Swagger UI to 3.17.1
2018-06-21 07:34:15 -07:00
Georg Ledermann
6b04c72cc9 ⬆️ Upgrade "swagger-ui" to 3.17.1 2018-06-21 09:11:06 +02:00
Richard Morris
890a31e749
Merge pull request #129 from hoshinotsuyoshi/fix_typo_readme
Fix typo in README
2018-05-30 18:16:01 -07:00
hoshinotsuyoshi
862ea53cf4 Fix typo in README
Fixed Gemfile example.
2018-05-31 08:54:12 +09:00
Richard Morris
254ade95db
Update README.md 2018-05-24 20:28:17 -07:00
Richard Morris
b9f71fe9b1
Merge pull request #117 from imRohan/master
Fixed typos in the swagger_helper.rb file
2018-05-24 20:00:10 -07:00
Richard Morris
870d467046
Merge pull request #125 from indocomsoft/patch-1
Fix travis to not cleanup when publishing rswag-ui
2018-05-24 19:59:56 -07:00
Julius Putra Tanu Setiaji
334671cb95
Fix travis to not cleanup when publishing rswag-ui
This is to keep `node_modules` directory.
2018-05-25 10:05:48 +08:00
domaindrivendev
efdfee5110 Tweak rswag-ui.gemspec to include node_modules 2018-05-24 09:31:06 -07:00
domaindrivendev
0c49c7e667 Ensure npm install runs during the deploy rswag-ui job 2018-05-24 08:58:19 -07:00
Richard Morris
e52ea0ba69
Update readme 2018-05-21 16:18:30 -07:00
domaindrivendev
9602db34fa Update readme in prep for 2.0.0 release 2018-05-21 16:16:20 -07:00
Richard Morris
d4b6848fa5
Merge pull request #122 from gouthamvel/patch-1
Add alternative way to load gem for optimization
2018-05-20 09:33:08 -07:00
goutham
799fc70d3a
Add alternative way to load gem for optimization
Most projects don't load rspec in production mode. So makes sense to add it to guide.
2018-05-20 18:22:06 +03:00
Richard Morris
6f8bbdbf2c
Merge pull request #121 from domaindrivendev/swagger-ui-3
swagger-ui as middleware & upgrade to 3.12.2
2018-05-17 09:11:12 -07:00
domaindrivendev
fee8491ab6 swagger-ui as middleware & upgrade to 3.12.2 2018-05-17 09:02:05 -07:00
domaindrivendev
4c708295b9 Update travis config to test against rails 5.2.0 2018-04-23 21:53:19 -07:00
domaindrivendev
c8e9ab3221 Add puma to Gemfile to fix integration tests 2018-04-23 16:24:43 -07:00
domaindrivendev
26a3bf5079 avoid metadata mutation in request_factory 2018-04-23 16:00:07 -07:00
Richard Morris
12daacf9a5
Merge pull request #112 from akurashev/master
Fix Authorization header missing and duplicating
2018-04-23 15:49:32 -07:00
Rohan Likhite
fee3b3bb84 fixed typos in the swagger_helper.rb file 2018-03-29 11:42:36 -04:00
Andrey Kurashev
05e1e2271f Fix Authorization header missing and duplicating 2018-02-20 14:49:13 +06:00
domaindrivendev
07ae261e54 Bump ruby patch version 2017-10-21 14:25:12 -07:00
domaindrivendev
06d00de992 Assume symbol for referenced parameter key 2017-09-06 13:38:36 -07:00
domaindrivendev
ad9cd5de66 Support paired security requirements - e.g. basic and apiKey 2017-08-21 01:07:47 -07:00
Tomasz Czernuszenko
3eda72155a Updated Readme.md:
Added a section on markdown formatting and and clarified some descriptions of API versioning
2017-08-07 14:12:40 +01:00
domaindrivendev
d91601b02c Merge pull request #87 from BC-THooper/allow_for_undefined_in_parameter_key
Allows for parameters to be defined without the 'in' key defined.
2017-07-31 17:54:43 -07:00
Travis Hooper
037c0e374a Allows for parameters to be defined without the 'in' key defined to allow for parameter 2017-07-31 17:44:43 -05:00
domaindrivendev
8f16492462 Merge pull request #82 from domaindrivendev/per-response-metadata
Allow arbitrary metadata for path/response blocks
2017-07-22 10:33:05 -07:00
domaindrivendev
732cab994c simplify validation blocks and use correct scope 2017-07-21 22:26:14 -07:00
domaindrivendev
452d9176cc Allow arbitrary metadata for path/response blocks 2017-07-21 21:19:25 -07:00
domaindrivendev
7f0e437f8b For rswag, param names MUST be unique 2017-07-21 21:04:46 -07:00
domaindrivendev
700b227231 Merge branch 'thg303-add-formData-support' 2017-07-21 14:25:51 -07:00
domaindrivendev
b16198377b Merge branch 'add-formData-support' of https://github.com/thg303/rswag into thg303-add-formData-support 2017-07-21 14:25:29 -07:00
domaindrivendev
e18a001e9b Move rackify headers to RequestFactory + other minor refactors 2017-07-21 13:49:01 -07:00
domaindrivendev
6ee53b08ae Merge branch 'refactor-request-factory' 2017-07-20 23:42:49 -07:00
domaindrivendev
97c2a39cfa Refactor request_factory & response_validator 2017-07-20 23:42:40 -07:00
Paul Carey
c9bda862b6 adds request spec generator shamelessly stollen from rspec-rails-swagger 2017-07-06 10:45:54 +01:00
Ali Qanavatian
44840ab836 Merge branch 'master' into add-formData-support 2017-07-04 09:45:33 +04:30
ali.q
182ee093f4 add formData support 2017-05-11 05:06:46 +04:30
andrew morton
4842055ee6 Add a contributing file
The exact sequence of commands to be able to run the tests wasn't obvious
to me so I'm assumiing others could use a hand.

I used the factory_girl_rails gem's file as a starting point.
2016-09-13 06:47:01 -06:00
151 changed files with 4123 additions and 38579 deletions

17
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@ -0,0 +1,17 @@
## Describe the bug
A clear and concise description of what the bug is.
## Steps to Test or Reproduce
Please provide an example repo or the steps to reproduce the behavior.
## Expected behavior
A clear and concise description of what you expected to happen.
## Screenshots
If applicable, add screenshots to help explain your problem.
## Additional context
Add any other context about the problem here.
## Rswag Version
The version of rswag are you using.

View File

@ -0,0 +1,11 @@
## Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is.
## Describe the solution you'd like
A clear and concise description of what you want to happen.
## Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
## Additional context
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,15 @@
## Problem
A clear and concise description of what the problem is.
## Solution
A clear and concise description of what the solution is.
### Related Issues
Links to any related issues.
### Checklist
- [ ] Added tests
- [ ] Changelog updated
### Steps to Test or Reproduce
Outline the steps to test or reproduce the PR here.

60
.github/workflows/ruby.yml vendored Normal file
View File

@ -0,0 +1,60 @@
name: Ruby
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
ruby: [2.6, 2.7, truffleruby-head]
rails: [5.2.4.4, 6.0.3.4]
env:
RAILS_VERSION: ${{ matrix.rails }}
steps:
- uses: actions/checkout@v2
- uses: ruby/setup-ruby@v1
with: { ruby-version: 2.6 }
- uses: actions/cache@v2
id: cache
with:
path: |
rswag-ui/node_modules
vendor/bundle
key: ${{ runner.os }}-ruby_${{ matrix.ruby }}-rails_${{ matrix.rails }}-${{ hashFiles('Gemfile', '**/package-lock.json') }}
- name: Install dependencies
run: |
gem update --system
bundle install
cd rswag-ui && npm install
- name: rswag-api
run: |
cd rswag-api
bundle exec rspec
- name: rswag-specs
if: success() || failure()
run: |
cd rswag-specs
bundle exec rspec
- name: rswag-ui
if: success() || failure()
run: |
cd rswag-ui
bundle exec rspec
- name: test-app
if: success() || failure()
run: |
cd test-app
bundle exec rake db:migrate db:test:prepare
bundle exec rspec

3
.gitignore vendored
View File

@ -3,5 +3,8 @@
**/*/*.gem **/*/*.gem
**/*/*.sqlite3 **/*/*.sqlite3
**/*/public/assets **/*/public/assets
**/*/node_modules
*.swp *.swp
Gemfile.lock Gemfile.lock
/.idea/
**/.byebug_history

View File

@ -1 +1 @@
2.3.0 2.7.2

View File

@ -1,23 +1,27 @@
language: ruby language: ruby
dist: bionic
services:
- xvfb
rvm: rvm:
- 2.2.5 - 2.6.3
env: env:
- RAILS_VERSION=5.1.2 - RAILS_VERSION=6.0.0
- RAILS_VERSION=4.2.0 - RAILS_VERSION=5.2.0
- RAILS_VERSION=3.2.22
addons:
apt:
packages:
- libqtwebkit-dev
- libqtwebkit4
cache: cache:
directories: directories:
- /home/travis/.rvm/gems/ruby-2.2.5 - /home/travis/.rvm/gems/ruby-2.6.3
install: bundle install install: ./ci/build.sh
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
- sleep 3
script: ./ci/test.sh script: ./ci/test.sh
@ -25,6 +29,7 @@ jobs:
include: include:
- stage: publish components - stage: publish components
script: 'cd rswag-api' script: 'cd rswag-api'
if: tag IS present
deploy: deploy:
gemspec: rswag-api.gemspec gemspec: rswag-api.gemspec
provider: rubygems provider: rubygems
@ -35,6 +40,7 @@ jobs:
- stage: publish components - stage: publish components
script: 'cd rswag-specs' script: 'cd rswag-specs'
if: tag IS present
deploy: deploy:
gemspec: rswag-specs.gemspec gemspec: rswag-specs.gemspec
provider: rubygems provider: rubygems
@ -45,16 +51,19 @@ jobs:
- stage: publish components - stage: publish components
script: 'cd rswag-ui' script: 'cd rswag-ui'
if: tag IS present
deploy: deploy:
gemspec: rswag-ui.gemspec gemspec: rswag-ui.gemspec
provider: rubygems provider: rubygems
api_key: $RUBYGEMS_API_KEY api_key: $RUBYGEMS_API_KEY
skip_cleanup: true
on: on:
branch: master branch: master
tags: true tags: true
- stage: publish rswag - stage: publish rswag
script: 'cd rswag' script: 'cd rswag'
if: tag IS present
deploy: deploy:
gemspec: rswag.gemspec gemspec: rswag.gemspec
provider: rubygems provider: rubygems

72
CHANGELOG.md Normal file
View File

@ -0,0 +1,72 @@
# rswag
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]
### Changed
- Update swagger-ui to 3.52.5
## [2.4.0] - 2021-02-09
### Added
- Added `SWAGGER_DRY_RUN` env variable [#274](https://github.com/rswag/rswag/pull/274)
## [2.3.3] - 2021-02-07
### Fixed
- Include response examples [#394](https://github.com/rswag/rswag/pull/394)
### Changed
- Update swagger-ui to 3.42.0
## [2.3.2] - 2021-01-27
### Added
- RequestBody now supports the `required` flag [#342](https://github.com/rswag/rswag/pull/342)
### Fixed
- Fix response example rendering [#330](https://github.com/rswag/rswag/pull/330)
- Fix empty content block [#347](https://github.com/rswag/rswag/pull/347)
## [2.3.1] - 2020-04-08
### Fixed
- Remove require for byebug [#295](https://github.com/rswag/rswag/issues/295)
## [2.3.0] - 2020-04-05
### Added
- Support for OpenAPI 3.0 ! [#286](https://github.com/rswag/rswag/pull/286)
- Custom headers in rswag-api [#187](https://github.com/rswag/rswag/pull/187)
- Allow document: false rspec metatag [#255](https://github.com/rswag/rswag/pull/255)
- Add parameterized pattern for spec files [#254](https://github.com/rswag/rswag/pull/254)
- Support Basic Auth on rswag-ui [#167](https://github.com/rswag/rswag/pull/167)
### Changed
- Update swagger-ui version to 3.23.11 [#239](https://github.com/rswag/rswag/pull/239)
- Rails constraint moved from < 6.1 to < 7 [#253](https://github.com/rswag/rswag/pull/253)
- Swaggerize now outputs base RSpec text on completion to avoid silent failures [#293](https://github.com/rswag/rswag/pull/293)
- Update swagger-ui version to 3.28.0
## [2.2.0] - 2019-11-01
### Added
- New swagger_format config option for setting YAML output [#251](https://github.com/rswag/rswag/pull/251)
### Changed
- rswag-api will serve yaml files as yaml [#251](https://github.com/rswag/rswag/pull/251)
## [2.1.1] - 2019-10-18
### Fixed
- Fix incorrect require reference for swagger_generator [#248](https://github.com/rswag/rswag/issues/248)
## [2.1.0] - 2019-10-17
### Added
- New Spec Generator [#75](https://github.com/rswag/rswag/pull/75)
- Support for Options and Trace verbs; You must use a framework that supports this, for Options Rails 6.1+ Rails 6 does not support Trace. [#237](https://github.com/rswag/rswag/pull/75)
### Changed
- Update swagger-ui to 3.18.2 [#240](https://github.com/rswag/rswag/pull/240)
## [2.0.6] - 2019-10-03
### Added
- Support for Rails 6 [#228](https://github.com/rswag/rswag/pull/228)
- Support for Windows paths [#176](https://github.com/rswag/rswag/pull/176)
### Changed
- Show response body when error code is not expected [#117](https://github.com/rswag/rswag/pull/177)
## [2.0.5] - 2018-07-10

83
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,83 @@
# Contributing
🎉 Thanks for taking the time to contribute! 🎉
We put forward the philosophy put forward by the [react community](https://reactcommunity.org/) about ownership, responsibility and avoiding burnout.
We also strive to achieve [semantic versioning](https://semver.org/) for this repo.
## Fork, then clone the repo:
```
git clone git@github.com:rswag/rswag.git
cd rswag
```
## Build
Set up your machine:
```
./ci/build.sh
```
Or manually
```
bundle
cd test-app
bundle exec rake db:setup
cd -
cd rswag-ui
npm install
cd -
```
## Test
Initialize the rswag-ui repo with assets.
```
ci/build.sh
```
Make sure the tests pass:
```
./ci/test.sh
```
or manually
```
cd test-app
bundle exec rspec
```
Make your change. Add tests for your change. Make the tests pass:
```
bundle exec rspec
```
Push to your fork and [submit a Pull Request][pr].
[pr]: https://github.com/rswag/rswag/compare/
## Updating Swagger UI
Find the latest versions of swagger-ui here:
https://github.com/swagger-api/swagger-ui/releases
Update the swagger-ui-dist version in the rswag-ui dependencies
```
./rswag-ui/package.json
```
Navigate to the rswag-ui folder and run npm install to update the package-lock.json
## Release
(for maintainers)
Update the changelog.md, putting the new version number in and moving the Unreleased marker.
Merge the changes into master you wish to release.
Add and push a new git tag, annotated tags preferred:
```
git tag -s 2.0.6 -m 'v2.0.6'
```
Travis will detect the tag and release all gems with that tag version number.

41
Gemfile
View File

@ -1,36 +1,51 @@
source "https://rubygems.org" # frozen_string_literal: true
source 'https://rubygems.org'
# Allow the rails version to come from an ENV setting so Travis can test multiple versions. # Allow the rails version to come from an ENV setting so Travis can test multiple versions.
# See http://www.schneems.com/post/50991826838/testing-against-multiple-rails-versions/ # See http://www.schneems.com/post/50991826838/testing-against-multiple-rails-versions/
rails_version = ENV['RAILS_VERSION'] || '5.1.2' rails_version = ENV['RAILS_VERSION'] || '5.2.4.2'
gem 'rails', "#{rails_version}" gem 'rails', rails_version.to_s
case rails_version.split('.').first case rails_version.split('.').first
when '3' when '3'
gem 'strong_parameters' gem 'strong_parameters'
when '4', '5' when '4', '5', '6'
gem 'responders' gem 'responders'
end end
gem 'sqlite3' case rails_version.split('.').first
when '3', '4', '5'
gem 'sqlite3', '~> 1.3.6'
when '6'
gem 'sqlite3', '~> 1.4.1'
end
gem 'rswag-specs', path: './rswag-specs'
gem 'rswag-api', path: './rswag-api' gem 'rswag-api', path: './rswag-api'
gem 'rswag-ui', path: './rswag-ui' gem 'rswag-ui', path: './rswag-ui'
# To use debugger group :development, :test do
# gem 'debugger' gem 'rswag-specs', path: './rswag-specs'
end
group :test do group :test do
gem 'test-unit'
gem 'rspec-rails'
gem 'generator_spec'
gem 'capybara' gem 'capybara'
gem 'capybara-webkit' gem 'geckodriver-helper'
gem 'generator_spec'
gem 'rspec-rails'
gem 'selenium-webdriver'
gem 'test-unit'
end
group :development do
gem 'rubocop'
end end
group :assets do group :assets do
gem 'mini_racer'
gem 'uglifier' gem 'uglifier'
gem 'therubyracer'
end end
gem 'byebug'
gem 'puma'

20
MIT-LICENCE Normal file
View File

@ -0,0 +1,20 @@
Copyright 2015 domaindrivendev
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

569
README.md
View File

@ -1,15 +1,69 @@
rswag (formerly swagger_rails) rswag
========= =========
[![Build Status](https://travis-ci.org/domaindrivendev/rswag.svg?branch=master)](https://travis-ci.org/domaindrivendev/rswag) [![Build Status](https://travis-ci.org/rswag/rswag.svg?branch=master)](https://travis-ci.org/rswag/rswag)
[![Maintainability](https://api.codeclimate.com/v1/badges/1175b984edc4610f82ab/maintainability)](https://codeclimate.com/github/rswag/rswag/maintainability)
[Swagger](http://swagger.io) tooling for Rails API's. Generate beautiful API documentation, including a UI to explore and test operations, directly from your rspec integration tests. OpenApi 3.0 and Swagger 2.0 compatible!
Seeking maintainers! Got a pet-bug that needs fixing? Just let us know in your issue/pr that you'd like to step up to help.
Rswag extends rspec-rails "request specs" with a Swagger-based DSL for describing and testing API operations. You describe your API operations with a succinct, intuitive syntax, and it automaticaly runs the tests. Once you have green tests, run a rake task to auto-generate corresponding Swagger files and expose them as YAML or JSON endpoints. Rswag also provides an embedded version of the awesome [swagger-ui](https://github.com/swagger-api/swagger-ui) that's powered by the exposed file. This toolchain makes it seamless to go from integration specs, which youre probably doing in some form already, to living documentation for your API consumers.
Api Rswag creates [Swagger](http://swagger.io) tooling for Rails API's. Generate beautiful API documentation, including a UI to explore and test operations, directly from your rspec integration tests.
Rswag extends rspec-rails "request specs" with a Swagger-based DSL for describing and testing API operations. You describe your API operations with a succinct, intuitive syntax, and it automaticaly runs the tests. Once you have green tests, run a rake task to auto-generate corresponding Swagger files and expose them as JSON endpoints. Rswag also provides an embedded version of the awesome [swagger-ui](https://github.com/swagger-api/swagger-ui) that's powered by the exposed JSON. This toolchain makes it seamless to go from integration specs, which youre probably doing in some form already, to living documentation for your API consumers.
And that's not all ... And that's not all ...
Once you have an API that can describe itself in Swagger, you've opened the treasure chest of Swagger-based tools including a client generator that can be targeted to a wide range of popular platforms. See [swagger-codegen](https://github.com/swagger-api/swagger-codegen) for more details. Once you have an API that can describe itself in Swagger, you've opened the treasure chest of Swagger-based tools including a client generator that can be targeted to a wide range of popular platforms. See [swagger-codegen](https://github.com/swagger-api/swagger-codegen) for more details.
## Compatibility ##
|Rswag Version|Swagger (OpenAPI) Spec.|swagger-ui|
|----------|----------|----------|
|[master](https://github.com/rswag/rswag/tree/master)|3.0.3|3.52.5|
|[2.3.0](https://github.com/rswag/rswag/tree/2.3.0)|3.0.3|3.23.11|
|[2.2.0](https://github.com/rswag/rswag/tree/2.2.0)|2.0|3.18.2|
|[1.6.0](https://github.com/rswag/rswag/tree/1.6.0)|2.0|2.2.5|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
**Table of Contents**
- [rswag](#rswag)
- [Compatibility](#compatibility)
- [Getting Started](#getting-started)
- [The rspec DSL](#the-rspec-dsl)
- [Paths, Operations and Responses](#paths-operations-and-responses)
- [Null Values](#null-values)
- [Support for oneOf, anyOf or AllOf schemas](#support-for-oneof-anyof-or-allof-schemas)
- [Global Metadata](#global-metadata)
- [Supporting multiple versions of API](#supporting-multiple-versions-of-api)
- [Formatting the description literals:](#formatting-the-description-literals)
- [Specifying/Testing API Security](#specifyingtesting-api-security)
- [Configuration & Customization](#configuration--customization)
- [Output Location for Generated Swagger Files](#output-location-for-generated-swagger-files)
- [Input Location for Rspec Tests](#input-location-for-rspec-tests)
- [Referenced Parameters and Schema Definitions](#referenced-parameters-and-schema-definitions)
- [Response headers](#response-headers)
- [Response examples](#response-examples)
- [Enable auto generation examples from responses](#enable-auto-generation-examples-from-responses)
- [Running tests without documenting](#running-tests-without-documenting)
- [rswag helper methods](#rswag-helper-methods)
- [rswag response examples](#rswag-response-examples)
- [Route Prefix for Swagger JSON Endpoints](#route-prefix-for-swagger-json-endpoints)
- [Root Location for Swagger Files](#root-location-for-swagger-files)
- [Dynamic Values for Swagger JSON](#dynamic-values-for-swagger-json)
- [Custom Headers for Swagger Files](#custom-headers-for-swagger-files)
- [Enable Swagger Endpoints for swagger-ui](#enable-swagger-endpoints-for-swagger-ui)
- [Enable Simple Basic Auth for swagger-ui](#enable-simple-basic-auth-for-swagger-ui)
- [Route Prefix for the swagger-ui](#route-prefix-for-the-swagger-ui)
- [Customizing the swagger-ui](#customizing-the-swagger-ui)
- [Serve UI Assets Directly from your Web Server](#serve-ui-assets-directly-from-your-web-server)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Getting Started ## ## Getting Started ##
1. Add this line to your applications _Gemfile_: 1. Add this line to your applications _Gemfile_:
@ -18,13 +72,36 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
gem 'rswag' gem 'rswag'
``` ```
or if you like to avoid loading rspec in other bundler groups load the rswag-specs component separately.
Note: Adding it to the :development group is not strictly necessary, but without it, generators and rake tasks must be preceded by RAILS_ENV=test.
```ruby
# Gemfile
gem 'rswag-api'
gem 'rswag-ui'
group :development, :test do
gem 'rspec-rails'
gem 'rswag-specs'
end
```
2. Run the install generator 2. Run the install generator
```ruby ```ruby
rails g rswag:install rails g rswag:install
``` ```
Or run the install generators for each package separately if you installed Rswag as separate gems, as indicated above:
```ruby
rails g rswag:api:install
rails g rswag:ui:install
RAILS_ENV=test rails g rswag:specs:install
```
3. Create an integration spec to describe and test your API. 3. Create an integration spec to describe and test your API.
There is also a generator which can help get you started `rails generate rspec:swagger API::MyController`
```ruby ```ruby
# spec/integration/blogs_spec.rb # spec/integration/blogs_spec.rb
@ -36,7 +113,7 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
post 'Creates a blog' do post 'Creates a blog' do
tags 'Blogs' tags 'Blogs'
consumes 'application/json', 'application/xml' consumes 'application/json'
parameter name: :blog, in: :body, schema: { parameter name: :blog, in: :body, schema: {
type: :object, type: :object,
properties: { properties: {
@ -61,9 +138,9 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
path '/blogs/{id}' do path '/blogs/{id}' do
get 'Retrieves a blog' do get 'Retrieves a blog' do
tags 'Blogs' tags 'Blogs', 'Another Tag'
produces 'application/json', 'application/xml' produces 'application/json', 'application/xml'
parameter name: :id, :in => :path, :type => :string parameter name: :id, in: :path, type: :string
response '200', 'blog found' do response '200', 'blog found' do
schema type: :object, schema type: :object,
@ -82,17 +159,30 @@ Once you have an API that can describe itself in Swagger, you've opened the trea
let(:id) { 'invalid' } let(:id) { 'invalid' }
run_test! run_test!
end end
response '406', 'unsupported accept header' do
let(:'Accept') { 'application/foo' }
run_test!
end
end end
end end
end end
``` ```
4. Generate the Swagger JSON file(s) 4. Generate the Swagger JSON file(s)
```ruby ```ruby
rake rswag:specs:swaggerize rake rswag:specs:swaggerize
``` ```
This common command is also aliased as `rake rswag`.
Or if you installed your gems separately:
```
RAILS_ENV=test rails rswag
```
5. Spin up your app and check out the awesome, auto-generated docs at _/api-docs_! 5. Spin up your app and check out the awesome, auto-generated docs at _/api-docs_!
## The rspec DSL ## ## The rspec DSL ##
@ -132,7 +222,7 @@ end
### Null Values ### ### Null Values ###
This library is currently using JSON::Draft4 for validation of response models. It does not support null as a value. So you can add the property 'x-nullable' to a definition to allow null/nil values to pass. This library is currently using JSON::Draft4 for validation of response models. Nullable properties can be supported with the non-standard property 'x-nullable' to a definition to allow null/nil values to pass. Or you can add the new standard ```nullable``` property to a definition.
```ruby ```ruby
describe 'Blogs API' do describe 'Blogs API' do
path '/blogs' do path '/blogs' do
@ -143,8 +233,8 @@ describe 'Blogs API' do
schema type: :object, schema type: :object,
properties: { properties: {
id: { type: :integer }, id: { type: :integer },
title: { type: :string }, title: { type: :string, nullable: true }, # preferred syntax
content: { type: :string, 'x-nullable': true } content: { type: :string, 'x-nullable': true } # legacy syntax, but still works
} }
.... ....
end end
@ -152,12 +242,45 @@ describe 'Blogs API' do
end end
end end
``` ```
*Note:* the OAI v3 may be released soon(ish?) and include a nullable property. This may have an effect on the need/use of custom extension to the draft. Do not use this property if you don't understand the implications.
<https://github.com/OAI/OpenAPI-Specification/issues/229#issuecomment-280376087> ### Support for oneOf, anyOf or AllOf schemas ###
Open API 3.0 now supports more flexible schema validation with the ```oneOf```, ```anyOf``` and ```allOf``` directives. rswag will handle these definitions and validate them properly.
Notice the ```schema``` inside the ```response``` section. Placing a ```schema``` method inside the response will validate (and fail the tests)
if during the integration test run the endpoint response does not match the response schema. This test validation can handle anyOf and allOf as well. See below:
```ruby
path '/blogs/flexible' do
post 'Creates a blog flexible body' do
tags 'Blogs'
description 'Creates a flexible blog from provided data'
operationId 'createFlexibleBlog'
consumes 'application/json'
produces 'application/json'
parameter name: :blog, in: :body, schema: {
oneOf: [
{ '$ref' => '#/components/schemas/blog' },
{ '$ref' => '#/components/schemas/flexible_blog' }
]
}
response '201', 'flexible blog created' do
schema oneOf: [{ '$ref' => '#/components/schemas/blog' }, { '$ref' => '#/components/schemas/flexible_blog' }]
run_test!
end
end
end
```
This automatic schema validation is a powerful feature of rswag.
### Global Metadata ### ### Global Metadata ###
In addition to paths, operations and responses, Swagger also supports global API metadata. When you install rswag, a file called _swagger_helper.rb_ is added to your spec folder. This is where you define one or more Swagger documents and provide global metadata. Again, the format is based on Swagger so most of the global fields supported by the top level ["Swagger" object](http://swagger.io/specification/#swaggerObject) can be provided with each document definition. As an example, you could define a Swagger document for each version of your API and in each case specify a title, version string and URL basePath: In addition to paths, operations and responses, Swagger also supports global API metadata. When you install rswag, a file called _swagger_helper.rb_ is added to your spec folder. This is where you define one or more Swagger documents and provide global metadata. Again, the format is based on Swagger so most of the global fields supported by the top level ["Swagger" object](http://swagger.io/specification/#swaggerObject) can be provided with each document definition. As an example, you could define a Swagger document for each version of your API and in each case specify a title, version string. In Open API 3.0 the pathing and server definitions have changed a bit [Swagger host/basePath](https://swagger.io/docs/specification/api-host-and-base-path/):
```ruby ```ruby
# spec/swagger_helper.rb # spec/swagger_helper.rb
@ -166,31 +289,52 @@ RSpec.configure do |config|
config.swagger_docs = { config.swagger_docs = {
'v1/swagger.json' => { 'v1/swagger.json' => {
swagger: '2.0', openapi: '3.0.1',
info: { info: {
title: 'API V1', title: 'API V1',
version: 'v1' version: 'v1',
description: 'This is the first version of my API'
}, },
basePath: '/api/v1' servers: [
{
url: 'https://{defaultHost}',
variables: {
defaultHost: {
default: 'www.example.com'
}
}
}
]
}, },
'v2/swagger.json' => { 'v2/swagger.yaml' => {
swagger: '2.0', openapi: '3.0.1',
info: { info: {
title: 'API V2', title: 'API V2',
version: 'v2' version: 'v2',
description: 'This is the second version of my API'
}, },
basePath: '/api/v2' servers: [
{
url: 'https://{defaultHost}',
variables: {
defaultHost: {
default: 'www.example.com'
}
}
}
]
} }
} }
end end
``` ```
__NOTE__: By default, the paths, operations and responses defined in your spec files will be associated with the first Swagger document in _swagger_helper.rb_. If you're using multiple documents, you'll need to tag the individual specs with their target document name: #### Supporting multiple versions of API ####
By default, the paths, operations and responses defined in your spec files will be associated with the first Swagger document in _swagger_helper.rb_. If your API has multiple versions, you should be using separate documents to describe each of them. In order to assign a file with a given version of API, you'll need to add the ```swagger_doc``` tag to each spec specifying its target document name:
```ruby ```ruby
# spec/integration/v2/blogs_spec.rb # spec/integration/v2/blogs_spec.rb
describe 'Blogs API', swagger_doc: 'v2/swagger.json' do describe 'Blogs API', swagger_doc: 'v2/swagger.yaml' do
path '/blogs' do path '/blogs' do
... ...
@ -200,9 +344,30 @@ describe 'Blogs API', swagger_doc: 'v2/swagger.json' do
end end
``` ```
#### Formatting the description literals: ####
Swagger supports the Markdown syntax to format strings. This can be especially handy if you were to provide a long description of a given API version or endpoint. Use [this guide](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) for reference.
__NOTE:__ There is one difference between the official Markdown syntax and Swagger interpretation, namely tables. To create a table like this:
| Column1 | Collumn2 |
| ------- | -------- |
| cell1 | cell2 |
you should use the folowing syntax, making sure there are no whitespaces at the start of any of the lines:
```
&#13;
| Column1 | Collumn2 |&#13;
| ------- | -------- |&#13;
| cell1 | cell2 |&#13;
&#13;
```
### Specifying/Testing API Security ### ### Specifying/Testing API Security ###
Swagger allows for the specification of different security schemes and their applicability to operations in an API. To leverage this in rswag, you define the schemes globally in _swagger_helper.rb_ and then use the "security" attribute at the operation level to specify which schemes, if any, are applicable to that operation. Swagger supports :basic, :apiKey and :oauth2 scheme types. See [the spec](http://swagger.io/specification/#security-definitions-object-109) for more info. Swagger allows for the specification of different security schemes and their applicability to operations in an API.
To leverage this in rswag, you define the schemes globally in _swagger_helper.rb_ and then use the "security" attribute at the operation level to specify which schemes, if any, are applicable to that operation.
Swagger supports :basic, :bearer, :apiKey and :oauth2 and :openIdConnect scheme types. See [the spec](https://swagger.io/docs/specification/authentication/) for more info, as this underwent major changes between Swagger 2.0 and Open API 3.0
```ruby ```ruby
# spec/swagger_helper.rb # spec/swagger_helper.rb
@ -211,15 +376,18 @@ RSpec.configure do |config|
config.swagger_docs = { config.swagger_docs = {
'v1/swagger.json' => { 'v1/swagger.json' => {
... ... # note the new Open API 3.0 compliant security structure here, under "components"
securityDefinitions: { components: {
basic: { securitySchemes: {
type: :basic basic_auth: {
}, type: :http,
apiKey: { scheme: :basic
type: :apiKey, },
name: 'api_key', api_key: {
in: :query type: :apiKey,
name: 'api_key',
in: :query
}
} }
} }
} }
@ -233,7 +401,7 @@ describe 'Blogs API' do
post 'Creates a blog' do post 'Creates a blog' do
tags 'Blogs' tags 'Blogs'
security [ basic: [] ] security [ basic_auth: [] ]
... ...
response '201', 'blog created' do response '201', 'blog created' do
@ -248,9 +416,35 @@ describe 'Blogs API' do
end end
end end
end end
# example of documenting an endpoint that handles basic auth and api key based security
describe 'Auth examples API' do
path '/auth-tests/basic-and-api-key' do
post 'Authenticates with basic auth and api key' do
tags 'Auth Tests'
operationId 'testBasicAndApiKey'
security [{ basic_auth: [], api_key: [] }]
response '204', 'Valid credentials' do
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
let(:api_key) { 'foobar' }
run_test!
end
response '401', 'Invalid credentials' do
let(:Authorization) { "Basic #{::Base64.strict_encode64('jsmith:jspass')}" }
let(:api_key) { 'barfoo' }
run_test!
end
end
end
end
``` ```
__NOTE:__ Depending on the scheme types, you'll be required to assign a corresponding parameter value with each example. For example, :basic auth is required above and so the :Authorization (header) parameter must be set accordingly __NOTE:__ Depending on the scheme types, you'll be required to assign a corresponding parameter value with each example.
For example, :basic auth is required above and so the :Authorization (header) parameter must be set accordingly
## Configuration & Customization ## ## Configuration & Customization ##
@ -259,7 +453,7 @@ The steps described above will get you up and running with minimal setup. Howeve
|Gem|Description|Added/Updated| |Gem|Description|Added/Updated|
|---------|-----------|-------------| |---------|-----------|-------------|
|__rswag-specs__|Swagger-based DSL for rspec & accompanying rake task for generating Swagger files|_spec/swagger_helper.rb_| |__rswag-specs__|Swagger-based DSL for rspec & accompanying rake task for generating Swagger files|_spec/swagger_helper.rb_|
|__rswag-api__ |Rails Engine that exposes your Swagger files as JSON endpoints|_config/initializers/rswag-api.rb, config/routes.rb_| |__rswag-api__ |Rails Engine that exposes your Swagger files as JSON endpoints|_config/initializers/rswag_api.rb, config/routes.rb_|
|__rswag-ui__ |Rails Engine that includes [swagger-ui](https://github.com/swagger-api/swagger-ui) and powers it from your Swagger endpoints|_config/initializers/rswag-ui.rb, config/routes.rb_| |__rswag-ui__ |Rails Engine that includes [swagger-ui](https://github.com/swagger-api/swagger-ui) and powers it from your Swagger endpoints|_config/initializers/rswag-ui.rb, config/routes.rb_|
### Output Location for Generated Swagger Files ### ### Output Location for Generated Swagger Files ###
@ -274,32 +468,65 @@ RSpec.configure do |config|
end end
``` ```
__NOTE__: If you do change this, you'll also need to update the rswag-api.rb initializer (assuming you're using rswag-api). More on this later. __NOTE__: If you do change this, you'll also need to update the rswag_api.rb initializer (assuming you're using rswag-api). More on this later.
### Input Location for Rspec Tests ###
By default, rswag will search for integration tests in _spec/requests_, _spec/api_ and _spec/integration_. If you want to use tests from other locations, provide the PATTERN argument to rake:
```ruby
# search for tests in spec/swagger
rake rswag:specs:swaggerize PATTERN="spec/swagger/**/*_spec.rb"
```
### Referenced Parameters and Schema Definitions ### ### Referenced Parameters and Schema Definitions ###
Swagger allows you to describe JSON structures inline with your operation descriptions OR as referenced globals. For example, you might have a standard response structure for all failed operations. Rather than repeating the schema in every operation spec, you can define it globally and provide a reference to it in each spec: Swagger allows you to describe JSON structures inline with your operation descriptions OR as referenced globals.
For example, you might have a standard response structure for all failed operations.
Again, this is a structure that changed since swagger 2.0. Notice the new "schemas" section for these.
Rather than repeating the schema in every operation spec, you can define it globally and provide a reference to it in each spec:
```ruby ```ruby
# spec/swagger_helper.rb # spec/swagger_helper.rb
config.swagger_docs = { config.swagger_docs = {
'v1/swagger.json' => { 'v1/swagger.json' => {
swagger: '2.0', openapi: '3.0.0',
info: { info: {
title: 'API V1' title: 'API V1'
}, },
definitions: { components: {
errors_object: { schemas: {
type: 'object', errors_object: {
properties: { type: 'object',
errors: { '$ref' => '#/definitions/errors_map' } properties: {
} errors: { '$ref' => '#/components/schemas/errors_map' }
}, }
errors_map: { },
type: 'object', errors_map: {
additionalProperties: { type: 'object',
type: 'array', additionalProperties: {
items: { type: 'string' } type: 'array',
items: { type: 'string' }
}
},
blog: {
type: 'object',
properties: {
id: { type: 'integer' },
title: { type: 'string' },
content: { type: 'string', nullable: true },
thumbnail: { type: 'string', nullable: true }
},
required: %w[id title]
},
new_blog: {
type: 'object',
properties: {
title: { type: 'string' },
content: { type: 'string', nullable: true },
thumbnail: { type: 'string', format: 'binary', nullable: true }
},
required: %w[title]
} }
} }
} }
@ -313,8 +540,10 @@ describe 'Blogs API' do
post 'Creates a blog' do post 'Creates a blog' do
parameter name: :new_blog, in: :body, schema: { '$ref' => '#/components/schemas/new_blog' }
response 422, 'invalid request' do response 422, 'invalid request' do
schema '$ref' => '#/definitions/errors_object' schema '$ref' => '#/components/schemas/errors_object'
... ...
end end
@ -326,14 +555,15 @@ describe 'Blogs API' do
post 'Creates a comment' do post 'Creates a comment' do
response 422, 'invalid request' do response 422, 'invalid request' do
schema '$ref' => '#/definitions/errors_object' schema '$ref' => '#/components/schemas/errors_object'
... ...
end end
``` ```
### Response headers ### ### Response headers ###
In Rswag, you could use `header` method inside the response block to specify header objects for this response. Rswag will validate your response headers with those header objects and inject them into the generated swagger file: In Rswag, you could use `header` method inside the response block to specify header objects for this response.
Rswag will validate your response headers with those header objects and inject them into the generated swagger file:
```ruby ```ruby
# spec/integration/comments_spec.rb # spec/integration/comments_spec.rb
@ -353,7 +583,7 @@ end
### Response examples ### ### Response examples ###
You can provide custom response examples to the generated swagger file by calling the method `examples` inside the response block: You can provide custom response examples to the generated swagger file by calling the method `examples` inside the response block:
However, auto generated example responses are now enabled by default in rswag. See below.
```ruby ```ruby
# spec/integration/blogs_spec.rb # spec/integration/blogs_spec.rb
describe 'Blogs API' do describe 'Blogs API' do
@ -372,22 +602,192 @@ describe 'Blogs API' do
end end
``` ```
### Enable generation examples from responses ###
### Enable auto generation examples from responses ###
To enable examples generation from responses add callback above run_test! like: To enable examples generation from responses add callback above run_test! like:
```ruby
```
after do |example| after do |example|
example.metadata[:response][:examples] = { 'application/json' => JSON.parse(response.body, symbolize_names: true) } example.metadata[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end end
``` ```
You need to disable --dry-run option for Rspec > 3
Add to application.rb: #### Dry Run Option ####
The `--dry-run` option is enabled by default for Rspec 3, but if you need to
disable it you can use the environment varible `SWAGGER_DRY_RUN=0` during the
generation command or add the following to your `config/environments/test.rb`:
```ruby ```ruby
RSpec.configure do |config| RSpec.configure do |config|
config.swagger_dry_run = false config.swagger_dry_run = false
end end
``` ```
#### Running tests without documenting ####
If you want to use Rswag for testing without adding it to you swagger docs, you can provide the document tag:
```ruby
describe 'Blogs API' do
path '/blogs/{blog_id}' do
get 'Retrieves a blog' do
# documentation is now disabled for this response only
response 200, 'blog found', document: false do
...
```
You can also reenable documentation for specific responses only:
```ruby
# documentation is now disabled
describe 'Blogs API', document: false do
path '/blogs/{blog_id}' do
get 'Retrieves a blog' do
# documentation is reenabled for this response only
response 200, 'blog found', document: true do
...
end
response 401, 'special case' do
...
end
```
##### rswag helper methods #####
<!--
There are some helper methods to help with documenting request bodies.
```ruby
describe 'Blogs API', type: :request, swagger_doc: 'v1/swagger.json' do
let(:api_key) { 'fake_key' }
path '/blogs' do
post 'Creates a blog' do
tags 'Blogs'
description 'Creates a new blog from provided data'
operationId 'createBlog'
consumes 'application/json'
produces 'application/json'
request_body_json schema: { '$ref' => '#/components/schemas/blog' },
examples: :blog
request_body_text_plain
request_body_xml schema: { '$ref' => '#/components/schemas/blog' }
let(:blog) { { blog: { title: 'foo', content: 'bar' } } }
response '201', 'blog created' do
schema '$ref' => '#/components/schemas/blog'
run_test!
end
response '422', 'invalid request' do
schema '$ref' => '#/components/schemas/errors_object'
let(:blog) { { blog: { title: 'foo' } } }
run_test! do |response|
expect(response.body).to include("can't be blank")
end
end
end
end
end
```
In the above example, we see methods ```request_body_json``` ```request_body_plain``` ```request_body_xml```.
These methods can be used to describe json, plain text and xml body. They are just wrapper methods to setup posting JSON, plain text or xml into your endpoint.
The simplest most common usage is for json formatted body to use the schema: to specify the location of the schema for the request body
and the examples: :blog which will create a named example "blog" under the "requestBody / content / application/json / examples" section.
Again, documenting request response examples changed in Open API 3.0. The example above would generate a swagger.json snippet that looks like this:
```json
...
{"requestBody": {
"required": true,
"content": {
"application/json": {
"examples": {
"blog": { // takes the name from examples: :blog above
"value": { //this is open api 3.0 structure -> https://swagger.io/docs/specification/adding-examples/
"blog": { // here is the actual JSON payload that is submitted to the service, and shows up in swagger UI as an example
"title": "foo",
"content": "bar"
}
}
}
},
"schema": {
"$ref": "#/components/schemas/blog"
}
},
"test/plain": {
"schema": {
"type": "string"
}
},
"application/xml": {
"schema": {
"$ref": "#/components/schemas/blog"
}
}
}
},
}
```
*NOTE:* for this example request body to work in the tests properly, you need to ``let`` a variable named *blog*.
The variable with the matching name (blog in this case) is eval-ed and captured to be placed in the examples section.
This ```let``` value is used in the integration test to run the test AND captured and injected into the requestBody section.
##### rswag response examples #####
In the same way that requestBody examples can be captured and injected into the swagger output, response examples can also be captured.
Using the above example, when the integration test is run - the swagger would include the following snippet providing more useful real world examples
capturing the response from the execution of the integration test. Again 3.0 swagger changed the structure of how these are documented.
```json
... "responses": {
"201": {
"description": "blog created",
"content": {
"application/json": {
"example": {
"id": 1,
"title": "foo",
"content": "bar",
"thumbnail": null
},
"schema": {
"$ref": "#/components/schemas/blog"
}
}
}
},
"422": {
"description": "invalid request",
"content": {
"application/json": {
"example": {
"errors": {
"content": [
"can't be blank"
]
}
},
"schema": {
"$ref": "#/components/schemas/errors_object"
}
}
}
}
}
```
-->
### Route Prefix for Swagger JSON Endpoints ### ### Route Prefix for Swagger JSON Endpoints ###
The functionality to expose Swagger files, such as those generated by rswag-specs, as JSON endpoints is implemented as a Rails Engine. As with any Engine, you can change it's mount prefix in _routes.rb_: The functionality to expose Swagger files, such as those generated by rswag-specs, as JSON endpoints is implemented as a Rails Engine. As with any Engine, you can change it's mount prefix in _routes.rb_:
@ -408,7 +808,7 @@ GET http://<hostname>/your-custom-prefix/v1/swagger.json
### Root Location for Swagger Files ### ### Root Location for Swagger Files ###
You can adjust this in the _rswag-api.rb_ initializer that's installed with __rspec-api__: You can adjust this in the _rswag_api.rb_ initializer that's installed with __rspec-api__:
```ruby ```ruby
Rswag::Api.configure do |c| Rswag::Api.configure do |c|
@ -431,7 +831,22 @@ Rswag::Api.configure do |c|
end end
``` ```
Note how the filter is passed the rack env for the current request. This provides a lot of flexibilty. For example, you can assign the "host" property (as shown) or you could inspect session information or an Authoriation header and remove operations based on user permissions. Note how the filter is passed the rack env for the current request. This provides a lot of flexibilty. For example, you can assign the "host" property (as shown) or you could inspect session information or an Authorization header and remove operations based on user permissions.
### Custom Headers for Swagger Files ###
You can specify custom headers for serving your generated Swagger JSON. For example you may want to force a specific charset for the 'Content-Type' header. You can configure a hash of headers to be sent with the request:
```ruby
Rswag::Api.configure do |c|
...
c.swagger_headers = { 'Content-Type' => 'application/json; charset=UTF-8' }
end
```
Take care when overriding Content-Type if you serve both YAML and JSON files as it will no longer switch the Content-Type header correctly.
### Enable Swagger Endpoints for swagger-ui ### ### Enable Swagger Endpoints for swagger-ui ###
@ -444,6 +859,17 @@ Rswag::Ui.configure do |c|
end end
``` ```
### Enable Simple Basic Auth for swagger-ui
You can also update the _rswag-ui.rb_ initializer, installed with rswag-ui to specify a username and password should you want to keep your documentation private.
```ruby
Rswag::Ui.configure do |c|
c.basic_auth_enabled = true
c.basic_auth_credentials 'username', 'password'
end
```
### Route Prefix for the swagger-ui ### ### Route Prefix for the swagger-ui ###
Similar to rswag-api, you can customize the swagger-ui path by changing it's mount prefix in _routes.rb_: Similar to rswag-api, you can customize the swagger-ui path by changing it's mount prefix in _routes.rb_:
@ -467,3 +893,24 @@ rails g rswag:ui:custom
``` ```
This will add a local version that you can modify at _app/views/rswag/ui/home/index.html.erb_ This will add a local version that you can modify at _app/views/rswag/ui/home/index.html.erb_
### Serve UI Assets Directly from your Web Server
Rswag ships with an embedded version of the [swagger-ui](https://github.com/swagger-api/swagger-ui), which is a static collection of JavaScript and CSS files. These assets are served by the rswag-ui middleware. However, for optimal performance you may want to serve them directly from your web server (e.g. Apache or NGINX). To do this, you'll need to copy them to the web server root. This is the "public" folder in a typical Rails application.
```
bundle exec rake rswag:ui:copy_assets[public/api-docs]
```
__NOTE:__: The provided subfolder MUST correspond to the UI mount prefix - "api-docs" by default.
Notes to test swagger output locally with swagger editor
```
docker pull swaggerapi/swagger-editor
```
```
docker run -d -p 80:8080 swaggerapi/swagger-editor
```
This will run the swagger editor in the docker daemon and can be accessed
at ```http://localhost```. From here, you can use the UI to load the generated swagger.json to validate the output.

24
ci/build.sh Executable file
View File

@ -0,0 +1,24 @@
#!/usr/bin/env bash
ROOT_PATH=$PWD
set -e # abort if anything fails
echo '####################'
echo 'bundle'
echo '####################'
echo ''
echo '##### all #####'
bundle install
echo '####################'
echo 'npm'
echo '####################'
echo ''
echo '##### rswag-ui #####'
cd $ROOT_PATH/rswag-ui
npm install
# Cleanup
cd $ROOT_PATH

View File

@ -5,4 +5,4 @@ Example:
rails generate rswag:api:install rails generate rswag:api:install
This will create: This will create:
config/initializers/rswag-api.rb config/initializers/rswag_api.rb

View File

@ -7,7 +7,7 @@ module Rswag
source_root File.expand_path('../templates', __FILE__) source_root File.expand_path('../templates', __FILE__)
def add_initializer def add_initializer
template('rswag-api.rb', 'config/initializers/rswag-api.rb') template('rswag_api.rb', 'config/initializers/rswag_api.rb')
end end
def add_routes def add_routes

View File

@ -1,7 +1,7 @@
module Rswag module Rswag
module Api module Api
class Configuration class Configuration
attr_accessor :swagger_root, :swagger_filter attr_accessor :swagger_root, :swagger_filter, :swagger_headers
def resolve_swagger_root(env) def resolve_swagger_root(env)
path_params = env['action_dispatch.request.path_parameters'] || {} path_params = env['action_dispatch.request.path_parameters'] || {}

View File

@ -1,8 +1,10 @@
require 'json' require 'json'
require 'yaml'
require 'rack/mime'
module Rswag module Rswag
module Api module Api
class Middleware class Middleware
def initialize(app, config) def initialize(app, config)
@app = app @app = app
@ -14,24 +16,47 @@ module Rswag
filename = "#{@config.resolve_swagger_root(env)}/#{path}" filename = "#{@config.resolve_swagger_root(env)}/#{path}"
if env['REQUEST_METHOD'] == 'GET' && File.file?(filename) if env['REQUEST_METHOD'] == 'GET' && File.file?(filename)
swagger = load_json(filename) swagger = parse_file(filename)
@config.swagger_filter.call(swagger, env) unless @config.swagger_filter.nil? @config.swagger_filter.call(swagger, env) unless @config.swagger_filter.nil?
mime = Rack::Mime.mime_type(::File.extname(path), 'text/plain')
headers = { 'Content-Type' => mime }.merge(@config.swagger_headers || {})
body = unload_swagger(filename, swagger)
return [ return [
'200', '200',
{ 'Content-Type' => 'application/json' }, headers,
[ JSON.dump(swagger) ] [ body ]
] ]
end end
return @app.call(env) return @app.call(env)
end end
private private
def parse_file(filename)
if /\.ya?ml$/ === filename
load_yaml(filename)
else
load_json(filename)
end
end
def load_yaml(filename)
YAML.safe_load(File.read(filename))
end
def load_json(filename) def load_json(filename)
JSON.parse(File.read(filename)) JSON.parse(File.read(filename))
end end
def unload_swagger(filename, swagger)
if /\.ya?ml$/ === filename
YAML.dump(swagger)
else
JSON.dump(swagger)
end
end
end end
end end
end end

View File

@ -1,17 +1,19 @@
$:.push File.expand_path("../lib", __FILE__) # frozen_string_literal: true
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
# Describe your gem and declare its dependencies: # Describe your gem and declare its dependencies:
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "rswag-api" s.name = 'rswag-api'
s.version = ENV['TRAVIS_TAG'] || '0.0.0' s.version = ENV['TRAVIS_TAG'] || '0.0.0'
s.authors = ["Richie Morris"] s.authors = ['Richie Morris', 'Greg Myers', 'Jay Danielian']
s.email = ["domaindrivendev@gmail.com"] s.email = ['domaindrivendev@gmail.com']
s.homepage = "https://github.com/domaindrivendev/rswag" s.homepage = 'https://github.com/rswag/rswag'
s.summary = "A Rails Engine that exposes Swagger files as JSON endpoints" s.summary = 'A Rails Engine that exposes OpenAPI (formerly called Swagger) files as JSON endpoints'
s.description = "Open up your API to the phenomenal Swagger ecosystem by exposing Swagger files, that describe your service, as JSON endpoints" s.description = 'Open up your API to the phenomenal OpenAPI ecosystem by exposing OpenAPI files, that describe your service, as JSON endpoints. More about the OpenAPI initiative here: http://spec.openapis.org/'
s.license = "MIT" s.license = 'MIT'
s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile"] s.files = Dir['{lib}/**/*'] + ['MIT-LICENSE', 'Rakefile']
s.add_dependency 'railties', '>= 3.1', '< 6.0' s.add_dependency 'railties', '>= 3.1', '< 7.1'
end end

View File

@ -1,6 +1,7 @@
require 'generator_spec' require 'generator_spec'
require 'generators/rswag/api/install/install_generator' require 'generators/rswag/api/install/install_generator'
module Rswag module Rswag
module Api module Api
@ -17,7 +18,7 @@ module Rswag
end end
it 'installs the Rails initializer' do it 'installs the Rails initializer' do
assert_file('config/initializers/rswag-api.rb') assert_file('config/initializers/rswag_api.rb')
end end
# Don't know how to test this # Don't know how to test this
@ -25,3 +26,4 @@ module Rswag
end end
end end
end end

View File

@ -1,5 +1,5 @@
{ {
"swagger": "2.0", "openapi": "3.0.1",
"info": { "info": {
"title": "API V1", "title": "API V1",
"version": "v1" "version": "v1"

View File

@ -0,0 +1,5 @@
swagger: '2.0'
info:
title: API V1
version: v1
paths: {}

View File

@ -37,6 +37,42 @@ module Rswag
end end
end end
context 'when swagger_headers is configured' do
let(:env) { env_defaults.merge('PATH_INFO' => 'v1/swagger.json') }
context 'replacing the default content type header' do
before do
config.swagger_headers = { 'Content-Type' => 'application/json; charset=UTF-8' }
end
it 'returns a 200 status' do
expect(response.length).to eql(3)
expect(response.first).to eql('200')
end
it 'applies the headers to the response' do
expect(response[1]).to include( 'Content-Type' => 'application/json; charset=UTF-8')
end
end
context 'adding an additional header' do
before do
config.swagger_headers = { 'Access-Control-Allow-Origin' => '*' }
end
it 'returns a 200 status' do
expect(response.length).to eql(3)
expect(response.first).to eql('200')
end
it 'applies the headers to the response' do
expect(response[1]).to include( 'Access-Control-Allow-Origin' => '*')
end
it 'keeps the default header' do
expect(response[1]).to include( 'Content-Type' => 'application/json')
end
end
end
context "given a path that doesn't map to any swagger file" do context "given a path that doesn't map to any swagger file" do
let(:env) { env_defaults.merge('PATH_INFO' => 'foobar.json') } let(:env) { env_defaults.merge('PATH_INFO' => 'foobar.json') }
before do before do
@ -61,7 +97,7 @@ module Rswag
it 'locates files at the provided swagger_root' do it 'locates files at the provided swagger_root' do
expect(response.length).to eql(3) expect(response.length).to eql(3)
expect(response[1]).to include( 'Content-Type' => 'application/json') expect(response[1]).to include( 'Content-Type' => 'application/json')
expect(response[2].join).to include('"swagger":"2.0"') expect(response[2].join).to include('"openapi":"3.0.1"')
end end
end end
@ -76,6 +112,21 @@ module Rswag
expect(response[2].join).to include('"host":"tempuri.org"') expect(response[2].join).to include('"host":"tempuri.org"')
end end
end end
context 'when a path maps to a yaml swagger file' do
let(:env) { env_defaults.merge('PATH_INFO' => 'v1/swagger.yml') }
it 'returns a 200 status' do
expect(response.length).to eql(3)
expect(response.first).to eql('200')
end
it 'returns contents of the swagger file' do
expect(response.length).to eql(3)
expect(response[1]).to include( 'Content-Type' => 'text/yaml')
expect(response[2].join).to include('title: API V1')
end
end
end end
end end
end end

View File

@ -20,8 +20,4 @@ RDoc::Task.new(:rdoc) do |rdoc|
rdoc.rdoc_files.include('lib/**/*.rb') rdoc.rdoc_files.include('lib/**/*.rb')
end end
Bundler::GemHelper.install_tasks Bundler::GemHelper.install_tasks

View File

@ -0,0 +1,9 @@
Description:
This creates an RSpec request spec to define Swagger documentation for a
controller. It will create a test for each of the controller's methods.
Example:
rails generate rspec:swagger V3::AccountsController
This will create:
spec/requests/v3/accounts_spec.rb

View File

@ -0,0 +1,24 @@
# frozen_string_literal: true
require 'rswag/route_parser'
require 'rails/generators'
module Rspec
class SwaggerGenerator < ::Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def setup
@routes = Rswag::RouteParser.new(controller_path).routes
end
def create_spec_file
template 'spec.rb', File.join('spec', 'requests', "#{controller_path}_spec.rb")
end
private
def controller_path
file_path.chomp('_controller')
end
end
end

View File

@ -0,0 +1,34 @@
require 'swagger_helper'
RSpec.describe '<%= controller_path %>', type: :request do
<% @routes.each do | template, path_item | %>
path '<%= template %>' do
<% unless path_item[:params].empty? -%>
# You'll want to customize the parameter types...
<% path_item[:params].each do |param| -%>
parameter name: '<%= param %>', in: :path, type: :string, description: '<%= param %>'
<% end -%>
<% end -%>
<% path_item[:actions].each do | action, details | %>
<%= action %>('<%= details[:summary] %>') do
response(200, 'successful') do
<% unless path_item[:params].empty? -%>
<% path_item[:params].each do |param| -%>
let(:<%= param %>) { '123' }
<% end -%>
<% end -%>
after do |example|
example.metadata[:response][:content] = {
'application/json' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end
end
<% end -%>
end
<% end -%>
end

View File

@ -1,10 +1,11 @@
# frozen_string_literal: true
require 'rails/generators' require 'rails/generators'
module Rswag module Rswag
module Specs module Specs
class InstallGenerator < Rails::Generators::Base class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__) source_root File.expand_path('templates', __dir__)
def add_swagger_helper def add_swagger_helper
template('swagger_helper.rb', 'spec/swagger_helper.rb') template('swagger_helper.rb', 'spec/swagger_helper.rb')

View File

@ -1,25 +1,43 @@
# frozen_string_literal: true
require 'rails_helper' require 'rails_helper'
RSpec.configure do |config| RSpec.configure do |config|
# Specify a root folder where Swagger JSON files are generated # Specify a root folder where Swagger JSON files are generated
# NOTE: If you're using the rswag-api to serve API descriptions, you'll need # NOTE: If you're using the rswag-api to serve API descriptions, you'll need
# to ensure that it's confiugred to server Swagger from the same folder # to ensure that it's configured to serve Swagger from the same folder
config.swagger_root = Rails.root.to_s + '/swagger' config.swagger_root = Rails.root.join('swagger').to_s
# Define one or more Swagger documents and provide global metadata for each one # Define one or more Swagger documents and provide global metadata for each one
# When you run the 'rswag:specs:to_swagger' rake task, the complete Swagger will # When you run the 'rswag:specs:swaggerize' rake task, the complete Swagger will
# be generated at the provided relative path under swagger_root # be generated at the provided relative path under swagger_root
# By default, the operations defined in spec files are added to the first # By default, the operations defined in spec files are added to the first
# document below. You can override this behavior by adding a swagger_doc tag to the # document below. You can override this behavior by adding a swagger_doc tag to the
# the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json' # the root example_group in your specs, e.g. describe '...', swagger_doc: 'v2/swagger.json'
config.swagger_docs = { config.swagger_docs = {
'v1/swagger.json' => { 'v1/swagger.yaml' => {
swagger: '2.0', openapi: '3.0.1',
info: { info: {
title: 'API V1', title: 'API V1',
version: 'v1' version: 'v1'
}, },
paths: {} paths: {},
servers: [
{
url: 'https://{defaultHost}',
variables: {
defaultHost: {
default: 'www.example.com'
}
}
}
]
} }
} }
# Specify the format of the output Swagger file when running 'rswag:specs:swaggerize'.
# The swagger_docs configuration option has the filename including format in
# the key, this may want to be changed to avoid putting yaml in json files.
# Defaults to json. Accepts ':json' and ':yaml'.
config.swagger_format = :yaml
end end

View File

@ -0,0 +1,60 @@
# frozen_string_literal: true
module Rswag
class RouteParser
attr_reader :controller
def initialize(controller)
@controller = controller
end
def routes
::Rails.application.routes.routes.select do |route|
route.defaults[:controller] == controller
end.each_with_object({}) do |route, tree|
path = path_from(route)
verb = verb_from(route)
tree[path] ||= { params: params_from(route), actions: {} }
tree[path][:actions][verb] = { summary: summary_from(route) }
tree
end
end
private
def path_from(route)
route.path.spec.to_s
.chomp('(.:format)') # Ignore any format suffix
.gsub(/:([^\/.?]+)/, '{\1}') # Convert :id to {id}
end
def verb_from(route)
verb = route.verb
if verb.is_a? String
verb.downcase
else
verb.source.gsub(/[$^]/, '').downcase
end
end
def summary_from(route)
verb = route.requirements[:action]
noun = route.requirements[:controller].split('/').last.singularize
# Apply a few customizations to make things more readable
case verb
when 'index'
verb = 'list'
noun = noun.pluralize
when 'destroy'
verb = 'delete'
end
"#{verb} #{noun}"
end
def params_from(route)
route.segments - ['format']
end
end
end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'rspec/core' require 'rspec/core'
require 'rswag/specs/example_group_helpers' require 'rswag/specs/example_group_helpers'
require 'rswag/specs/example_helpers' require 'rswag/specs/example_helpers'
@ -6,12 +8,12 @@ require 'rswag/specs/railtie' if defined?(Rails::Railtie)
module Rswag module Rswag
module Specs module Specs
# Extend RSpec with a swagger-based DSL # Extend RSpec with a swagger-based DSL
::RSpec.configure do |c| ::RSpec.configure do |c|
c.add_setting :swagger_root c.add_setting :swagger_root
c.add_setting :swagger_docs c.add_setting :swagger_docs
c.add_setting :swagger_dry_run c.add_setting :swagger_dry_run
c.add_setting :swagger_format
c.extend ExampleGroupHelpers, type: :request c.extend ExampleGroupHelpers, type: :request
c.include ExampleHelpers, type: :request c.include ExampleHelpers, type: :request
end end

View File

@ -1,8 +1,8 @@
# frozen_string_literal: true
module Rswag module Rswag
module Specs module Specs
class Configuration class Configuration
def initialize(rspec_config) def initialize(rspec_config)
@rspec_config = rspec_config @rspec_config = rspec_config
end end
@ -12,6 +12,7 @@ module Rswag
if @rspec_config.swagger_root.nil? if @rspec_config.swagger_root.nil?
raise ConfigurationError, 'No swagger_root provided. See swagger_helper.rb' raise ConfigurationError, 'No swagger_root provided. See swagger_helper.rb'
end end
@rspec_config.swagger_root @rspec_config.swagger_root
end end
end end
@ -21,21 +22,39 @@ module Rswag
if @rspec_config.swagger_docs.nil? || @rspec_config.swagger_docs.empty? if @rspec_config.swagger_docs.nil? || @rspec_config.swagger_docs.empty?
raise ConfigurationError, 'No swagger_docs defined. See swagger_helper.rb' raise ConfigurationError, 'No swagger_docs defined. See swagger_helper.rb'
end end
@rspec_config.swagger_docs @rspec_config.swagger_docs
end end
end end
def swagger_dry_run def swagger_dry_run
@swagger_dry_run ||= begin return @swagger_dry_run if defined? @swagger_dry_run
@rspec_config.swagger_dry_run.nil? || @rspec_config.swagger_dry_run if ENV.key?('SWAGGER_DRY_RUN')
@rspec_config.swagger_dry_run = ENV['SWAGGER_DRY_RUN'] == '1'
end
@swagger_dry_run = @rspec_config.swagger_dry_run.nil? || @rspec_config.swagger_dry_run
end
def swagger_format
@swagger_format ||= begin
@rspec_config.swagger_format = :json if @rspec_config.swagger_format.nil? || @rspec_config.swagger_format.empty?
raise ConfigurationError, "Unknown swagger_format '#{@rspec_config.swagger_format}'" unless [:json, :yaml].include?(@rspec_config.swagger_format)
@rspec_config.swagger_format
end end
end end
def get_swagger_doc(name) def get_swagger_doc(name)
return swagger_docs.values.first if name.nil? return swagger_docs.values.first if name.nil?
raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name] raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name]
swagger_docs[name] swagger_docs[name]
end end
def get_swagger_doc_version(name)
doc = get_swagger_doc(name)
doc[:openapi] || doc[:swagger]
end
end end
class ConfigurationError < StandardError; end class ConfigurationError < StandardError; end

View File

@ -1,20 +1,21 @@
# frozen_string_literal: true
module Rswag module Rswag
module Specs module Specs
module ExampleGroupHelpers module ExampleGroupHelpers
def path(template, metadata = {}, &block)
def path(template, &block) metadata[:path_item] = { template: template }
api_metadata = { path_item: { template: template } } describe(template, metadata, &block)
describe(template, api_metadata, &block)
end end
[ :get, :post, :patch, :put, :delete, :head ].each do |verb| [:get, :post, :patch, :put, :delete, :head, :options, :trace].each do |verb|
define_method(verb) do |summary, &block| define_method(verb) do |summary, &block|
api_metadata = { operation: { verb: verb, summary: summary } } api_metadata = { operation: { verb: verb, summary: summary } }
describe(verb, api_metadata, &block) describe(verb, api_metadata, &block)
end end
end end
[ :operationId, :deprecated, :security ].each do |attr_name| [:operationId, :deprecated, :security].each do |attr_name|
define_method(attr_name) do |value| define_method(attr_name) do |value|
metadata[:operation][attr_name] = value metadata[:operation][attr_name] = value
end end
@ -23,22 +24,25 @@ module Rswag
# NOTE: 'description' requires special treatment because ExampleGroup already # NOTE: 'description' requires special treatment because ExampleGroup already
# defines a method with that name. Provide an override that supports the existing # defines a method with that name. Provide an override that supports the existing
# functionality while also setting the appropriate metadata if applicable # functionality while also setting the appropriate metadata if applicable
def description(value=nil) def description(value = nil)
return super() if value.nil? return super() if value.nil?
metadata[:operation][:description] = value metadata[:operation][:description] = value
end end
# These are array properties - note the splat operator # These are array properties - note the splat operator
[ :tags, :consumes, :produces, :schemes ].each do |attr_name| [:tags, :consumes, :produces, :schemes].each do |attr_name|
define_method(attr_name) do |*value| define_method(attr_name) do |*value|
metadata[:operation][attr_name] = value metadata[:operation][attr_name] = value
end end
end end
def parameter(attributes) def parameter(attributes)
attributes[:required] = true if attributes[:in].to_sym == :path if attributes[:in] && attributes[:in].to_sym == :path
attributes[:required] = true
end
if metadata.has_key?(:operation) if metadata.key?(:operation)
metadata[:operation][:parameters] ||= [] metadata[:operation][:parameters] ||= []
metadata[:operation][:parameters] << attributes metadata[:operation][:parameters] << attributes
else else
@ -47,9 +51,9 @@ module Rswag
end end
end end
def response(code, description, &block) def response(code, description, metadata = {}, &block)
api_metadata = { response: { code: code, description: description } } metadata[:response] = { code: code, description: description }
context(description, api_metadata, &block) context(description, metadata, &block)
end end
def schema(value) def schema(value)
@ -58,6 +62,7 @@ module Rswag
def header(name, attributes) def header(name, attributes)
metadata[:response][:headers] ||= {} metadata[:response][:headers] ||= {}
metadata[:response][:headers][name] = attributes metadata[:response][:headers][name] = attributes
end end
@ -66,7 +71,11 @@ module Rswag
# rspec-core ExampleGroup # rspec-core ExampleGroup
def examples(example = nil) def examples(example = nil)
return super() if example.nil? return super() if example.nil?
metadata[:response][:examples] = example
metadata[:response][:content] =
example.each_with_object({}) do |(mime, example_object), memo|
memo[mime] = { example: example_object }
end
end end
def run_test!(&block) def run_test!(&block)
@ -77,7 +86,8 @@ module Rswag
end end
it "returns a #{metadata[:response][:code]} response" do it "returns a #{metadata[:response][:code]} response" do
assert_response_matches_metadata(example.metadata, &block) assert_response_matches_metadata(metadata)
block.call(response) if block_given?
end end
else else
before do |example| before do |example|
@ -86,6 +96,7 @@ module Rswag
it "returns a #{metadata[:response][:code]} response" do |example| it "returns a #{metadata[:response][:code]} response" do |example|
assert_response_matches_metadata(example.metadata, &block) assert_response_matches_metadata(example.metadata, &block)
example.instance_exec(response, &block) if block_given?
end end
end end
end end

View File

@ -1,59 +1,33 @@
# frozen_string_literal: true
require 'rswag/specs/request_factory' require 'rswag/specs/request_factory'
require 'rswag/specs/response_validator' require 'rswag/specs/response_validator'
module Rswag module Rswag
module Specs module Specs
module ExampleHelpers module ExampleHelpers
def submit_request(metadata)
def submit_request(api_metadata) request = RequestFactory.new.build_request(metadata, self)
global_metadata = rswag_config.get_swagger_doc(api_metadata[:swagger_doc])
factory = RequestFactory.new(api_metadata, global_metadata)
if RAILS_VERSION < 5 if RAILS_VERSION < 5
send( send(
api_metadata[:operation][:verb], request[:verb],
factory.build_fullpath(self), request[:path],
factory.build_body(self), request[:payload],
rackify_headers(factory.build_headers(self)) # Rails test infrastructure requires Rack headers request[:headers]
) )
else else
send( send(
api_metadata[:operation][:verb], request[:verb],
factory.build_fullpath(self), request[:path],
{ params: request[:payload],
params: factory.build_body(self), headers: request[:headers]
headers: factory.build_headers(self)
}
) )
end end
end end
def assert_response_matches_metadata(api_metadata, &block) def assert_response_matches_metadata(metadata)
global_metadata = rswag_config.get_swagger_doc(api_metadata[:swagger_doc]) ResponseValidator.new.validate!(metadata, response)
validator = ResponseValidator.new(api_metadata, global_metadata)
validator.validate!(response, &block)
end
private
def rackify_headers(headers)
name_value_pairs = headers.map do |name, value|
[
case name
when 'Accept' then 'HTTP_ACCEPT'
when 'Content-Type' then 'CONTENT_TYPE'
when 'Authorization' then 'HTTP_AUTHORIZATION'
else name
end,
value
]
end
Hash[ name_value_pairs ]
end
def rswag_config
::Rswag::Specs.config
end end
end end
end end

View File

@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'json-schema' require 'json-schema'
module Rswag module Rswag
module Specs module Specs
class ExtendedSchema < JSON::Schema::Draft4 class ExtendedSchema < JSON::Schema::Draft4
def initialize def initialize
super super
@attributes['type'] = ExtendedTypeAttribute @attributes['type'] = ExtendedTypeAttribute
@ -13,9 +14,9 @@ module Rswag
end end
class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
def self.validate(current_schema, data, fragments, processor, validator, options = {})
def self.validate(current_schema, data, fragments, processor, validator, options={}) return if data.nil? && (current_schema.schema['nullable'] == true || current_schema.schema['x-nullable'] == true)
return if data.nil? && current_schema.schema['x-nullable'] == true
super super
end end
end end

View File

@ -1,9 +1,14 @@
# frozen_string_literal: true
module Rswag module Rswag
module Specs module Specs
class Railtie < ::Rails::Railtie class Railtie < ::Rails::Railtie
rake_tasks do rake_tasks do
load File.expand_path('../../../tasks/rswag-specs_tasks.rake', __FILE__) load File.expand_path('../../tasks/rswag-specs_tasks.rake', __dir__)
end
generators do
require 'generators/rspec/swagger_generator.rb'
end end
end end
end end

View File

@ -1,100 +1,126 @@
# frozen_string_literal: true
require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/slice'
require 'active_support/core_ext/hash/conversions'
require 'json' require 'json'
module Rswag module Rswag
module Specs module Specs
class RequestFactory class RequestFactory
def initialize(config = ::Rswag::Specs.config)
def initialize(api_metadata, global_metadata) @config = config
@api_metadata = api_metadata
@global_metadata = global_metadata
end end
def build_fullpath(example) def build_request(metadata, example)
@api_metadata[:path_item][:template].dup.tap do |t| swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
t.prepend(@global_metadata[:basePath] || '') parameters = expand_parameters(metadata, swagger_doc, example)
parameters_in(:path).each { |p| t.gsub!("{#{p[:name]}}", example.send(p[:name]).to_s) }
t.concat(build_query_string(example)) {}.tap do |request|
add_verb(request, metadata)
add_path(request, metadata, swagger_doc, parameters, example)
add_headers(request, metadata, swagger_doc, parameters, example)
add_payload(request, parameters, example)
end end
end end
def build_query_string(example)
query_string = parameters_in(:query)
.select { |p| p.fetch(:required, true) ||
example.respond_to?(p[:name]) }
.map { |p| build_query_string_part(p, example.send(p[:name])) }
.join('&')
query_string.empty? ? '' : "?#{query_string}"
end
def build_body(example)
body_parameter = parameters_in(:body).first
body_parameter.nil? ? '' : example.send(body_parameter[:name]).to_json
end
def build_headers(example)
name_value_pairs = parameters_in(:header).map do |param|
[
param[:name],
example.send(param[:name]).to_s
]
end
# Add MIME type headers based on produces/consumes metadata
produces = @api_metadata[:operation][:produces] || @global_metadata[:produces]
consumes = @api_metadata[:operation][:consumes] || @global_metadata[:consumes]
name_value_pairs << [ 'Accept', produces.join(';') ] unless produces.nil?
name_value_pairs << [ 'Content-Type', consumes.join(';') ] unless consumes.nil?
Hash[ name_value_pairs ]
end
private private
def parameters_in(location) def expand_parameters(metadata, swagger_doc, example)
path_item_params = @api_metadata[:path_item][:parameters] || [] operation_params = metadata[:operation][:parameters] || []
operation_params = @api_metadata[:operation][:parameters] || [] path_item_params = metadata[:path_item][:parameters] || []
applicable_params = operation_params security_params = derive_security_params(metadata, swagger_doc)
.concat(path_item_params)
.uniq { |p| p[:name] } # operation params should override path_item params
applicable_params # NOTE: Use of + instead of concat to avoid mutation of the metadata object
.map { |p| p['$ref'] ? resolve_parameter(p['$ref']) : p } # resolve any references (operation_params + path_item_params + security_params)
.concat(security_parameters) .map { |p| p['$ref'] ? resolve_parameter(p['$ref'], swagger_doc) : p }
.select { |p| p[:in] == location } .uniq { |p| p[:name] }
.reject { |p| p[:required] == false && !example.respond_to?(p[:name]) }
end end
def resolve_parameter(ref) def derive_security_params(metadata, swagger_doc)
defined_params = @global_metadata[:parameters] requirements = metadata[:operation][:security] || swagger_doc[:security] || []
key = ref.sub('#/parameters/', '') scheme_names = requirements.flat_map(&:keys)
raise "Referenced parameter '#{ref}' must be defined" unless defined_params && defined_params[key] schemes = security_version(scheme_names, swagger_doc)
defined_params[key]
schemes.map do |scheme|
param = (scheme[:type] == :apiKey) ? scheme.slice(:name, :in) : { name: 'Authorization', in: :header }
param.merge(type: :string, required: requirements.one?)
end
end end
def security_parameters def security_version(scheme_names, swagger_doc)
applicable_security_schemes.map do |scheme| if doc_version(swagger_doc).start_with?('2')
if scheme[:type] == :apiKey (swagger_doc[:securityDefinitions] || {}).slice(*scheme_names).values
{ name: scheme[:name], type: :string, in: scheme[:in] } else # Openapi3
if swagger_doc.key?(:securityDefinitions)
ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: securityDefinitions is replaced in OpenAPI3! Rename to components/securitySchemes (in swagger_helper.rb)')
swagger_doc[:components] ||= { securitySchemes: swagger_doc[:securityDefinitions] }
swagger_doc.delete(:securityDefinitions)
end
components = swagger_doc[:components] || {}
(components[:securitySchemes] || {}).slice(*scheme_names).values
end
end
def resolve_parameter(ref, swagger_doc)
key = key_version(ref, swagger_doc)
definitions = definition_version(swagger_doc)
raise "Referenced parameter '#{ref}' must be defined" unless definitions && definitions[key]
definitions[key]
end
def key_version(ref, swagger_doc)
if doc_version(swagger_doc).start_with?('2')
ref.sub('#/parameters/', '').to_sym
else # Openapi3
if ref.start_with?('#/parameters/')
ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: #/parameters/ refs are replaced in OpenAPI3! Rename to #/components/parameters/')
ref.sub('#/parameters/', '').to_sym
else else
{ name: 'Authorization', type: :string, in: :header } # use auth header for basic & oauth2 ref.sub('#/components/parameters/', '').to_sym
end end
end end
end end
def applicable_security_schemes def definition_version(swagger_doc)
# First figure out the security requirement applicable to the operation if doc_version(swagger_doc).start_with?('2')
requirements = @api_metadata[:operation][:security] || @global_metadata[:security] swagger_doc[:parameters]
scheme_names = requirements ? requirements.map { |r| r.keys.first } : [] else # Openapi3
if swagger_doc.key?(:parameters)
ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: parameters is replaced in OpenAPI3! Rename to components/parameters (in swagger_helper.rb)')
swagger_doc[:parameters]
else
components = swagger_doc[:components] || {}
components[:parameters]
end
end
end
# Then obtain the scheme definitions for those requirements def add_verb(request, metadata)
(@global_metadata[:securityDefinitions] || {}).slice(*scheme_names).values request[:verb] = metadata[:operation][:verb]
end
def add_path(request, metadata, swagger_doc, parameters, example)
template = (swagger_doc[:basePath] || '') + metadata[:path_item][:template]
request[:path] = template.tap do |path_template|
parameters.select { |p| p[:in] == :path }.each do |p|
path_template.gsub!("{#{p[:name]}}", example.send(p[:name]).to_s)
end
parameters.select { |p| p[:in] == :query }.each_with_index do |p, i|
path_template.concat(i.zero? ? '?' : '&')
path_template.concat(build_query_string_part(p, example.send(p[:name])))
end
end
end end
def build_query_string_part(param, value) def build_query_string_part(param, value)
return "#{param[:name]}=#{value.to_s}" unless param[:type].to_sym == :array
name = param[:name] name = param[:name]
type = param[:type] || param.dig(:schema, :type)
return "#{name}=#{value}" unless type&.to_sym == :array
case param[:collectionFormat] case param[:collectionFormat]
when :ssv when :ssv
"#{name}=#{value.join(' ')}" "#{name}=#{value.join(' ')}"
@ -108,6 +134,96 @@ module Rswag
"#{name}=#{value.join(',')}" # csv is default "#{name}=#{value.join(',')}" # csv is default
end end
end end
def add_headers(request, metadata, swagger_doc, parameters, example)
tuples = parameters
.select { |p| p[:in] == :header }
.map { |p| [p[:name], example.send(p[:name]).to_s] }
# Accept header
produces = metadata[:operation][:produces] || swagger_doc[:produces]
if produces
accept = example.respond_to?(:Accept) ? example.send(:Accept) : produces.first
tuples << ['Accept', accept]
end
# Content-Type header
consumes = metadata[:operation][:consumes] || swagger_doc[:consumes]
if consumes
content_type = example.respond_to?(:'Content-Type') ? example.send(:'Content-Type') : consumes.first
tuples << ['Content-Type', content_type]
end
# Rails test infrastructure requires rackified headers
rackified_tuples = tuples.map do |pair|
[
case pair[0]
when 'Accept' then 'HTTP_ACCEPT'
when 'Content-Type' then 'CONTENT_TYPE'
when 'Authorization' then 'HTTP_AUTHORIZATION'
else pair[0]
end,
pair[1]
]
end
request[:headers] = Hash[rackified_tuples]
end
def add_payload(request, parameters, example)
content_type = request[:headers]['CONTENT_TYPE']
return if content_type.nil?
if ['application/x-www-form-urlencoded', 'multipart/form-data'].include?(content_type)
request[:payload] = build_form_payload(parameters, example)
else
request[:payload] = build_json_payload(parameters, example)
end
end
def build_form_payload(parameters, example)
# See http://seejohncode.com/2012/04/29/quick-tip-testing-multipart-uploads-with-rspec/
# Rather that serializing with the appropriate encoding (e.g. multipart/form-data),
# Rails test infrastructure allows us to send the values directly as a hash
# PROS: simple to implement, CONS: serialization/deserialization is bypassed in test
tuples = parameters
.select { |p| p[:in] == :formData }
.map { |p| [p[:name], example.send(p[:name])] }
Hash[tuples]
end
def build_json_payload(parameters, example)
body_param = parameters.select { |p| p[:in] == :body }.first
return nil unless body_param
raise(MissingParameterError, body_param[:name]) unless example.respond_to?(body_param[:name])
example.send(body_param[:name]).to_json
end
def doc_version(doc)
doc[:openapi] || doc[:swagger] || '3'
end
end
class MissingParameterError < StandardError
attr_reader :body_param
def initialize(body_param)
@body_param = body_param
end
def message
<<~MSG
Missing parameter '#{body_param}'
Please check your spec. It looks like you defined a body parameter,
but did not declare usage via let. Try adding:
let(:#{body_param}) {}
MSG
end
end end
end end
end end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
require 'active_support/core_ext/hash/slice' require 'active_support/core_ext/hash/slice'
require 'json-schema' require 'json-schema'
require 'json' require 'json'
@ -6,46 +8,66 @@ require 'rswag/specs/extended_schema'
module Rswag module Rswag
module Specs module Specs
class ResponseValidator class ResponseValidator
def initialize(config = ::Rswag::Specs.config)
def initialize(api_metadata, global_metadata) @config = config
@api_metadata = api_metadata
@global_metadata = global_metadata
end end
def validate!(response, &block) def validate!(metadata, response)
validate_code!(response.code) swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
validate_headers!(response.headers)
validate_body!(response.body, &block) validate_code!(metadata, response)
block.call(response) if block_given? validate_headers!(metadata, response.headers)
validate_body!(metadata, swagger_doc, response.body)
end end
private private
def validate_code!(code) def validate_code!(metadata, response)
if code.to_s != @api_metadata[:response][:code].to_s expected = metadata[:response][:code].to_s
raise UnexpectedResponse, "Expected response code '#{code}' to match '#{@api_metadata[:response][:code]}'" if response.code != expected
raise UnexpectedResponse,
"Expected response code '#{response.code}' to match '#{expected}'\n" \
"Response body: #{response.body}"
end end
end end
def validate_headers!(headers) def validate_headers!(metadata, headers)
header_schema = @api_metadata[:response][:headers] expected = (metadata[:response][:headers] || {}).keys
return if header_schema.nil? expected.each do |name|
raise UnexpectedResponse, "Expected response header #{name} to be present" if headers[name.to_s].nil?
header_schema.keys.each do |header_name|
raise UnexpectedResponse, "Expected response header #{header_name} to be present" if headers[header_name.to_s].nil?
end end
end end
def validate_body!(body) def validate_body!(metadata, swagger_doc, body)
response_schema = @api_metadata[:response][:schema] response_schema = metadata[:response][:schema]
return if response_schema.nil? return if response_schema.nil?
version = @config.get_swagger_doc_version(metadata[:swagger_doc])
schemas = definitions_or_component_schemas(swagger_doc, version)
validation_schema = response_schema validation_schema = response_schema
.merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema') .merge('$schema' => 'http://tempuri.org/rswag/specs/extended_schema')
.merge(@global_metadata.slice(:definitions)) .merge(schemas)
error_messages = JSON::Validator.fully_validate(validation_schema, body)
if error_messages.any? errors = JSON::Validator.fully_validate(validation_schema, body)
raise UnexpectedResponse, "Expected response body to match schema: #{error_messages[0]}" return unless errors.any?
raise UnexpectedResponse,
"Expected response body to match schema: #{errors[0]}\n" \
"Response body: #{JSON.pretty_generate(JSON.parse(body))}"
end
def definitions_or_component_schemas(swagger_doc, version)
if version.start_with?('2')
swagger_doc.slice(:definitions)
else # Openapi3
if swagger_doc.key?(:definitions)
ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: definitions is replaced in OpenAPI3! Rename to components/schemas (in swagger_helper.rb)')
swagger_doc.slice(:definitions)
else
components = swagger_doc[:components] || {}
{ components: components }
end
end end
end end
end end

View File

@ -1,9 +1,12 @@
# frozen_string_literal: true
require 'active_support/core_ext/hash/deep_merge' require 'active_support/core_ext/hash/deep_merge'
require 'rspec/core/formatters/base_text_formatter'
require 'swagger_helper' require 'swagger_helper'
module Rswag module Rswag
module Specs module Specs
class SwaggerFormatter class SwaggerFormatter < ::RSpec::Core::Formatters::BaseTextFormatter
# NOTE: rspec 2.x support # NOTE: rspec 2.x support
if RSPEC_VERSION > 2 if RSPEC_VERSION > 2
@ -19,25 +22,62 @@ module Rswag
def example_group_finished(notification) def example_group_finished(notification)
# NOTE: rspec 2.x support # NOTE: rspec 2.x support
if RSPEC_VERSION > 2 metadata = if RSPEC_VERSION > 2
metadata = notification.group.metadata notification.group.metadata
else else
metadata = notification.metadata notification.metadata
end end
return unless metadata.has_key?(:response) # !metadata[:document] won't work, since nil means we should generate
# docs.
return if metadata[:document] == false
return unless metadata.key?(:response)
swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc]) swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
unless doc_version(swagger_doc).start_with?('2')
# This is called multiple times per file!
# metadata[:operation] is also re-used between examples within file
# therefore be careful NOT to modify its content here.
upgrade_request_type!(metadata)
upgrade_servers!(swagger_doc)
upgrade_oauth!(swagger_doc)
upgrade_response_produces!(swagger_doc, metadata)
end
swagger_doc.deep_merge!(metadata_to_swagger(metadata)) swagger_doc.deep_merge!(metadata_to_swagger(metadata))
end end
def stop(notification=nil) def stop(_notification = nil)
@config.swagger_docs.each do |url_path, doc| @config.swagger_docs.each do |url_path, doc|
unless doc_version(doc).start_with?('2')
doc[:paths]&.each_pair do |_k, v|
v.each_pair do |_verb, value|
is_hash = value.is_a?(Hash)
if is_hash && value.dig(:parameters)
schema_param = value.dig(:parameters)&.find { |p| (p[:in] == :body || p[:in] == :formData) && p[:schema] }
mime_list = value.dig(:consumes) || doc[:consumes]
if value && schema_param && mime_list
value[:requestBody] = { content: {} } unless value.dig(:requestBody, :content)
value[:requestBody][:required] = true if schema_param[:required]
mime_list.each do |mime|
value[:requestBody][:content][mime] = { schema: schema_param[:schema] }
end
end
value[:parameters].reject! { |p| p[:in] == :body || p[:in] == :formData }
end
remove_invalid_operation_keys!(value)
end
end
end
file_path = File.join(@config.swagger_root, url_path) file_path = File.join(@config.swagger_root, url_path)
dirname = File.dirname(file_path) dirname = File.dirname(file_path)
FileUtils.mkdir_p dirname unless File.exists?(dirname) FileUtils.mkdir_p dirname unless File.exist?(dirname)
File.open(file_path, 'w') do |file| File.open(file_path, 'w') do |file|
file.write(JSON.pretty_generate(doc)) file.write(pretty_generate(doc))
end end
@output.puts "Swagger doc generated at #{file_path}" @output.puts "Swagger doc generated at #{file_path}"
@ -46,22 +86,119 @@ module Rswag
private private
def pretty_generate(doc)
if @config.swagger_format == :yaml
clean_doc = yaml_prepare(doc)
YAML.dump(clean_doc)
else # config errors are thrown in 'def swagger_format', no throw needed here
JSON.pretty_generate(doc)
end
end
def yaml_prepare(doc)
json_doc = JSON.pretty_generate(doc)
JSON.parse(json_doc)
end
def metadata_to_swagger(metadata) def metadata_to_swagger(metadata)
response_code = metadata[:response][:code] response_code = metadata[:response][:code]
response = metadata[:response].reject { |k,v| k == :code } response = metadata[:response].reject { |k, _v| k == :code }
verb = metadata[:operation][:verb] verb = metadata[:operation][:verb]
operation = metadata[:operation] operation = metadata[:operation]
.reject { |k,v| k == :verb } .reject { |k, _v| k == :verb }
.merge(responses: { response_code => response }) .merge(responses: { response_code => response })
path_template = metadata[:path_item][:template] path_template = metadata[:path_item][:template]
path_item = metadata[:path_item] path_item = metadata[:path_item]
.reject { |k,v| k == :template } .reject { |k, _v| k == :template }
.merge(verb => operation) .merge(verb => operation)
{ paths: { path_template => path_item } } { paths: { path_template => path_item } }
end end
def doc_version(doc)
doc[:openapi] || doc[:swagger] || '3'
end
def upgrade_response_produces!(swagger_doc, metadata)
# Accept header
mime_list = Array(metadata[:operation][:produces] || swagger_doc[:produces])
target_node = metadata[:response]
upgrade_content!(mime_list, target_node)
metadata[:response].delete(:schema)
end
def upgrade_content!(mime_list, target_node)
schema = target_node[:schema]
return if mime_list.empty? || schema.nil?
target_node[:content] ||= {}
mime_list.each do |mime_type|
# TODO upgrade to have content-type specific schema
(target_node[:content][mime_type] ||= {}).merge!(schema: schema)
end
end
def upgrade_request_type!(metadata)
# No deprecation here as it seems valid to allow type as a shorthand
operation_nodes = metadata[:operation][:parameters] || []
path_nodes = metadata[:path_item][:parameters] || []
header_node = metadata[:response][:headers] || {}
(operation_nodes + path_nodes + [header_node]).each do |node|
if node && node[:type] && node[:schema].nil?
node[:schema] = { type: node[:type] }
node.delete(:type)
end
end
end
def upgrade_servers!(swagger_doc)
return unless swagger_doc[:servers].nil? && swagger_doc.key?(:schemes)
ActiveSupport::Deprecation.warn('Rswag::Specs: WARNING: schemes, host, and basePath are replaced in OpenAPI3! Rename to array of servers[{url}] (in swagger_helper.rb)')
swagger_doc[:servers] = { urls: [] }
swagger_doc[:schemes].each do |scheme|
swagger_doc[:servers][:urls] << scheme + '://' + swagger_doc[:host] + swagger_doc[:basePath]
end
swagger_doc.delete(:schemes)
swagger_doc.delete(:host)
swagger_doc.delete(:basePath)
end
def upgrade_oauth!(swagger_doc)
# find flow in securitySchemes (securityDefinitions will have been re-written)
schemes = swagger_doc.dig(:components, :securitySchemes)
return unless schemes&.any? { |_k, v| v.key?(:flow) }
schemes.each do |name, v|
next unless v.key?(:flow)
ActiveSupport::Deprecation.warn("Rswag::Specs: WARNING: securityDefinitions flow is replaced in OpenAPI3! Rename to components/securitySchemes/#{name}/flows[] (in swagger_helper.rb)")
flow = swagger_doc[:components][:securitySchemes][name].delete(:flow).to_s
if flow == 'accessCode'
ActiveSupport::Deprecation.warn("Rswag::Specs: WARNING: securityDefinitions accessCode is replaced in OpenAPI3! Rename to clientCredentials (in swagger_helper.rb)")
flow = 'authorizationCode'
end
if flow == 'application'
ActiveSupport::Deprecation.warn("Rswag::Specs: WARNING: securityDefinitions application is replaced in OpenAPI3! Rename to authorizationCode (in swagger_helper.rb)")
flow = 'clientCredentials'
end
flow_elements = swagger_doc[:components][:securitySchemes][name].except(:type).each_with_object({}) do |(k, _v), a|
a[k] = swagger_doc[:components][:securitySchemes][name].delete(k)
end
swagger_doc[:components][:securitySchemes][name].merge!(flows: { flow => flow_elements })
end
end
def remove_invalid_operation_keys!(value)
is_hash = value.is_a?(Hash)
value.delete(:consumes) if is_hash && value.dig(:consumes)
value.delete(:produces) if is_hash && value.dig(:produces)
end
end end
end end
end end

View File

@ -1,18 +1,24 @@
# frozen_string_literal: true
require 'rspec/core/rake_task' require 'rspec/core/rake_task'
namespace :rswag do namespace :rswag do
namespace :specs do namespace :specs do
desc 'Generate Swagger JSON files from integration specs' desc 'Generate Swagger JSON files from integration specs'
RSpec::Core::RakeTask.new('swaggerize') do |t| RSpec::Core::RakeTask.new('swaggerize') do |t|
t.pattern = 'spec/requests/**/*_spec.rb, spec/api/**/*_spec.rb, spec/integration/**/*_spec.rb' t.pattern = ENV.fetch(
'PATTERN',
'spec/requests/**/*_spec.rb, spec/api/**/*_spec.rb, spec/integration/**/*_spec.rb'
)
# NOTE: rspec 2.x support # NOTE: rspec 2.x support
if Rswag::Specs::RSPEC_VERSION > 2 && Rswag::Specs.config.swagger_dry_run if Rswag::Specs::RSPEC_VERSION > 2 && Rswag::Specs.config.swagger_dry_run
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined' ] t.rspec_opts = ['--format Rswag::Specs::SwaggerFormatter', '--dry-run', '--order defined']
else else
t.rspec_opts = [ '--format Rswag::Specs::SwaggerFormatter', '--order defined' ] t.rspec_opts = ['--format Rswag::Specs::SwaggerFormatter', '--order defined']
end end
end end
end end
end end
task rswag: ['rswag:specs:swaggerize']

View File

@ -1,19 +1,21 @@
$:.push File.expand_path("../lib", __FILE__) # frozen_string_literal: true
$LOAD_PATH.push File.expand_path('lib', __dir__)
# Describe your gem and declare its dependencies: # Describe your gem and declare its dependencies:
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "rswag-specs" s.name = 'rswag-specs'
s.version = ENV['TRAVIS_TAG'] || '0.0.0' s.version = ENV['TRAVIS_TAG'] || '0.0.0'
s.authors = ["Richie Morris"] s.authors = ['Richie Morris', 'Greg Myers', 'Jay Danielian']
s.email = ["domaindrivendev@gmail.com"] s.email = ['domaindrivendev@gmail.com']
s.homepage = "https://github.com/domaindrivendev/rswag" s.homepage = 'https://github.com/rswag/rswag'
s.summary = "A Swagger-based DSL for rspec-rails & accompanying rake task for generating Swagger files" s.summary = 'An OpenAPI-based (formerly called Swagger) DSL for rspec-rails & accompanying rake task for generating OpenAPI specification files'
s.description = "Simplify API integration testing with a succinct rspec DSL and generate Swagger files directly from your rspecs" s.description = 'Simplify API integration testing with a succinct rspec DSL and generate OpenAPI specification files directly from your rspecs. More about the OpenAPI initiative here: http://spec.openapis.org/'
s.license = "MIT" s.license = 'MIT'
s.files = Dir["{lib}/**/*"] + ["MIT-LICENSE", "Rakefile" ] s.files = Dir['{lib}/**/*'] + ['MIT-LICENSE', 'Rakefile']
s.add_dependency 'activesupport', '>= 3.1', '< 6.0' s.add_dependency 'activesupport', '>= 3.1', '< 7.1'
s.add_dependency 'railties', '>= 3.1', '< 6.0' s.add_dependency 'railties', '>= 3.1', '< 7.1'
s.add_dependency 'json-schema', '~> 2.2' s.add_dependency 'json-schema', '~> 2.2'
end end

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
require 'generator_spec'
require 'generators/rspec/swagger_generator'
require 'tmpdir'
module Rspec
describe SwaggerGenerator do
include GeneratorSpec::TestCase
destination Dir.mktmpdir
before(:all) do
prepare_destination
fixtures_dir = File.expand_path('fixtures', __dir__)
FileUtils.cp_r("#{fixtures_dir}/spec", destination_root)
end
after(:all) do
end
it 'installs the swagger_helper for rspec' do
allow_any_instance_of(Rswag::RouteParser).to receive(:routes).and_return(fake_routes)
run_generator ['Posts::CommentsController']
assert_file('spec/requests/posts/comments_spec.rb') do |content|
assert_match(/parameter name: 'post_id', in: :path, type: :string/, content)
assert_match(/patch\('update_comments comment'\)/, content)
end
end
private
def fake_routes
{
'/posts/{post_id}/comments/{id}' => {
params: ['post_id', 'id'],
actions: {
'get' => { summary: 'show comment' },
'patch' => { summary: 'update_comments comment' }
}
}
}
end
end
end

View File

@ -1,16 +1,17 @@
# frozen_string_literal: true
require 'generator_spec' require 'generator_spec'
require 'generators/rswag/specs/install/install_generator' require 'generators/rswag/specs/install/install_generator'
module Rswag module Rswag
module Specs module Specs
RSpec.describe InstallGenerator do
describe InstallGenerator do
include GeneratorSpec::TestCase include GeneratorSpec::TestCase
destination File.expand_path('../tmp', __FILE__) destination File.expand_path('tmp', __dir__)
before(:all) do before(:all) do
prepare_destination prepare_destination
fixtures_dir = File.expand_path('../fixtures', __FILE__) fixtures_dir = File.expand_path('fixtures', __dir__)
FileUtils.cp_r("#{fixtures_dir}/spec", destination_root) FileUtils.cp_r("#{fixtures_dir}/spec", destination_root)
run_generator run_generator

View File

@ -0,0 +1,50 @@
# frozen_string_literal: true
RSpec.describe Rswag::RouteParser do
describe "#routes" do
let(:controller) { "api/v1/posts" }
subject { described_class.new(controller) }
let(:routes) do
[
double(
defaults: {
controller: controller
},
path: double(
spec: double(
to_s: "/api/v1/posts/:id(.:format)"
)
),
verb: "GET",
requirements: {
action: "show",
controller: "api/v1/posts"
},
segments: ["id", "format"]
)
]
end
let(:expectation) do
{
"/api/v1/posts/{id}" => {
params: ["id"],
actions: {
"get" => {
summary: "show post"
}
}
}
}
end
before do
allow(::Rails).to receive_message_chain("application.routes.routes") { routes }
end
it "returns correct routes" do
expect(subject.routes).to eq(expectation)
end
end
end

View File

@ -1,12 +1,15 @@
# frozen_string_literal: true
require 'rswag/specs/configuration' require 'rswag/specs/configuration'
module Rswag module Rswag
module Specs module Specs
RSpec.describe Configuration do
describe Configuration do
subject { described_class.new(rspec_config) } subject { described_class.new(rspec_config) }
let(:rspec_config) { OpenStruct.new(swagger_root: swagger_root, swagger_docs: swagger_docs) } let(:rspec_config) do
OpenStruct.new(swagger_root: swagger_root, swagger_docs: swagger_docs, swagger_format: swagger_format)
end
let(:swagger_root) { 'foobar' } let(:swagger_root) { 'foobar' }
let(:swagger_docs) do let(:swagger_docs) do
{ {
@ -14,6 +17,7 @@ module Rswag
'v2/swagger.json' => { info: { title: 'v2' } } 'v2/swagger.json' => { info: { title: 'v2' } }
} }
end end
let(:swagger_format) { :yaml }
describe '#swagger_root' do describe '#swagger_root' do
let(:response) { subject.swagger_root } let(:response) { subject.swagger_root }
@ -46,6 +50,26 @@ module Rswag
end end
end end
describe '#swagger_format' do
let(:response) { subject.swagger_format }
context 'provided in rspec config' do
it { expect(response).to be_an_instance_of(Symbol) }
end
context 'unsupported format provided' do
let(:swagger_format) { :xml }
it { expect { response }.to raise_error ConfigurationError }
end
context 'not provided' do
let(:swagger_format) { nil }
it { expect(response).to eq(:json) }
end
end
describe '#get_swagger_doc(tag=nil)' do describe '#get_swagger_doc(tag=nil)' do
let(:swagger_doc) { subject.get_swagger_doc(tag) } let(:swagger_doc) { subject.get_swagger_doc(tag) }

View File

@ -1,9 +1,10 @@
# frozen_string_literal: true
require 'rswag/specs/example_group_helpers' require 'rswag/specs/example_group_helpers'
module Rswag module Rswag
module Specs module Specs
RSpec.describe ExampleGroupHelpers do
describe ExampleGroupHelpers do
subject { double('example_group') } subject { double('example_group') }
before do before do
@ -24,7 +25,7 @@ module Rswag
end end
end end
describe '#get|post|patch|put|delete|head(verb, summary)' do describe '#get|post|patch|put|delete|head|options|trace(verb, summary)' do
before { subject.post('Creates a blog') } before { subject.post('Creates a blog') }
it "delegates to 'describe' with 'operation' metadata" do it "delegates to 'describe' with 'operation' metadata" do
@ -34,31 +35,6 @@ module Rswag
end end
end end
describe '#tags|description|operationId|consumes|produces|schemes|deprecated(value)' do
before do
subject.tags('Blogs', 'Admin')
subject.description('Some description')
subject.operationId('createBlog')
subject.consumes('application/json', 'application/xml')
subject.produces('application/json', 'application/xml')
subject.schemes('http', 'https')
subject.deprecated(true)
end
let(:api_metadata) { { operation: {} } }
it "adds to the 'operation' metadata" do
expect(api_metadata[:operation]).to match(
tags: [ 'Blogs', 'Admin' ],
description: 'Some description',
operationId: 'createBlog',
consumes: [ 'application/json', 'application/xml' ],
produces: [ 'application/json', 'application/xml' ],
schemes: [ 'http', 'https' ],
deprecated: true
)
end
end
describe '#tags|description|operationId|consumes|produces|schemes|deprecated|security(value)' do describe '#tags|description|operationId|consumes|produces|schemes|deprecated|security(value)' do
before do before do
subject.tags('Blogs', 'Admin') subject.tags('Blogs', 'Admin')
@ -74,12 +50,12 @@ module Rswag
it "adds to the 'operation' metadata" do it "adds to the 'operation' metadata" do
expect(api_metadata[:operation]).to match( expect(api_metadata[:operation]).to match(
tags: [ 'Blogs', 'Admin' ], tags: ['Blogs', 'Admin'],
description: 'Some description', description: 'Some description',
operationId: 'createBlog', operationId: 'createBlog',
consumes: [ 'application/json', 'application/xml' ], consumes: ['application/json', 'application/xml'],
produces: [ 'application/json', 'application/xml' ], produces: ['application/json', 'application/xml'],
schemes: [ 'http', 'https' ], schemes: ['http', 'https'],
deprecated: true, deprecated: true,
security: { api_key: [] } security: { api_key: [] }
) )
@ -87,14 +63,13 @@ module Rswag
end end
describe '#parameter(attributes)' do describe '#parameter(attributes)' do
context "when called at the 'path' level" do context "when called at the 'path' level" do
before { subject.parameter(name: :blog, in: :body, schema: { type: 'object' }) } before { subject.parameter(name: :blog, in: :body, schema: { type: 'object' }) }
let(:api_metadata) { { path_item: {} } } # i.e. operation not defined yet let(:api_metadata) { { path_item: {} } } # i.e. operation not defined yet
it "adds to the 'path_item parameters' metadata" do it "adds to the 'path_item parameters' metadata" do
expect(api_metadata[:path_item][:parameters]).to match( expect(api_metadata[:path_item][:parameters]).to match(
[ name: :blog, in: :body, schema: { type: 'object' } ] [name: :blog, in: :body, schema: { type: 'object' }]
) )
end end
end end
@ -105,7 +80,7 @@ module Rswag
it "adds to the 'operation parameters' metadata" do it "adds to the 'operation parameters' metadata" do
expect(api_metadata[:operation][:parameters]).to match( expect(api_metadata[:operation][:parameters]).to match(
[ name: :blog, in: :body, schema: { type: 'object' } ] [name: :blog, in: :body, schema: { type: 'object' }]
) )
end end
end end
@ -116,10 +91,19 @@ module Rswag
it "automatically sets the 'required' flag" do it "automatically sets the 'required' flag" do
expect(api_metadata[:operation][:parameters]).to match( expect(api_metadata[:operation][:parameters]).to match(
[ name: :id, in: :path, required: true ] [name: :id, in: :path, required: true]
) )
end end
end end
context "when 'in' parameter key is not defined" do
before { subject.parameter(name: :id) }
let(:api_metadata) { { operation: {} } }
it "does not require the 'in' parameter key" do
expect(api_metadata[:operation][:parameters]).to match([name: :id])
end
end
end end
describe '#response(code, description)' do describe '#response(code, description)' do
@ -153,9 +137,10 @@ module Rswag
end end
describe '#examples(example)' do describe '#examples(example)' do
let(:mime) { 'application/json' }
let(:json_example) do let(:json_example) do
{ {
'application/json' => { mime => {
foo: 'bar' foo: 'bar'
} }
} }
@ -167,7 +152,11 @@ module Rswag
end end
it "adds to the 'response examples' metadata" do it "adds to the 'response examples' metadata" do
expect(api_metadata[:response][:examples]).to eq(json_example) expect(api_metadata[:response][:content]).to match(
mime => {
example: json_example[mime]
}
)
end end
end end
end end

View File

@ -1,25 +1,39 @@
# frozen_string_literal: true
require 'rswag/specs/example_helpers' require 'rswag/specs/example_helpers'
module Rswag module Rswag
module Specs module Specs
RSpec.describe ExampleHelpers do
describe ExampleHelpers do
subject { double('example') } subject { double('example') }
before do before do
subject.extend ExampleHelpers subject.extend(ExampleHelpers)
# Mock out some infrastructure allow(Rswag::Specs).to receive(:config).and_return(config)
stub_const('Rails::VERSION::MAJOR', 3) allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
rswag_config = double('rswag_config') stub_const('Rswag::Specs::RAILS_VERSION', 3)
allow(rswag_config).to receive(:get_swagger_doc).and_return(global_metadata)
allow(subject).to receive(:rswag_config).and_return(rswag_config)
end end
let(:api_metadata) do let(:config) { double('config') }
let(:swagger_doc) do
{
swagger: '2.0',
securityDefinitions: {
api_key: {
type: :apiKey,
name: 'api_key',
in: :query
}
}
}
end
let(:metadata) do
{ {
path_item: { template: '/blogs/{blog_id}/comments/{id}' }, path_item: { template: '/blogs/{blog_id}/comments/{id}' },
operation: { operation: {
verb: :put, verb: :put,
summary: 'Updates a blog', summary: 'Updates a blog',
consumes: ['application/json'],
parameters: [ parameters: [
{ name: :blog_id, in: :path, type: 'integer' }, { name: :blog_id, in: :path, type: 'integer' },
{ name: 'id', in: :path, type: 'integer' }, { name: 'id', in: :path, type: 'integer' },
@ -32,19 +46,8 @@ module Rswag
} }
} }
end end
let(:global_metadata) do
{
securityDefinitions: {
api_key: {
type: :apiKey,
name: 'api_key',
in: :query
}
}
}
end
describe '#submit_request(api_metadata)' do describe '#submit_request(metadata)' do
before do before do
allow(subject).to receive(:blog_id).and_return(1) allow(subject).to receive(:blog_id).and_return(1)
allow(subject).to receive(:id).and_return(2) allow(subject).to receive(:id).and_return(2)
@ -52,14 +55,14 @@ module Rswag
allow(subject).to receive(:api_key).and_return('fookey') allow(subject).to receive(:api_key).and_return('fookey')
allow(subject).to receive(:blog).and_return(text: 'Some comment') allow(subject).to receive(:blog).and_return(text: 'Some comment')
allow(subject).to receive(:put) allow(subject).to receive(:put)
subject.submit_request(api_metadata) subject.submit_request(metadata)
end end
it "submits a request built from metadata and 'let' values" do it "submits a request built from metadata and 'let' values" do
expect(subject).to have_received(:put).with( expect(subject).to have_received(:put).with(
'/blogs/1/comments/2?q1=foo&api_key=fookey', '/blogs/1/comments/2?q1=foo&api_key=fookey',
"{\"text\":\"Some comment\"}", '{"text":"Some comment"}',
{} { 'CONTENT_TYPE' => 'application/json' }
) )
end end
end end

View File

@ -1,268 +1,419 @@
# frozen_string_literal: true
require 'rswag/specs/request_factory' require 'rswag/specs/request_factory'
module Rswag module Rswag
module Specs module Specs
RSpec.describe RequestFactory do
describe RequestFactory do subject { RequestFactory.new(config) }
subject { RequestFactory.new(api_metadata, global_metadata) }
before do before do
allow(example).to receive(:blog_id).and_return(1) allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
allow(example).to receive(:id).and_return('2')
end end
let(:api_metadata) do let(:config) { double('config') }
let(:swagger_doc) { { swagger: '2.0' } }
let(:example) { double('example') }
let(:metadata) do
{ {
path_item: { template: '/blogs/{blog_id}/comments/{id}' }, path_item: { template: '/blogs' },
operation: { operation: { verb: :get }
verb: :put,
summary: 'Updates a blog',
parameters: [
{ name: :blog_id, in: :path, type: 'integer' },
{ name: 'id', in: :path, type: 'integer' }
]
}
} }
end end
let(:global_metadata) { {} }
let(:example) { double('example') }
describe '#build_fullpath(example)' do describe '#build_request(metadata, example)' do
let(:path) { subject.build_fullpath(example) } let(:request) { subject.build_request(metadata, example) }
context 'always' do it 'builds request hash for given example' do
it "builds a path using metadata and example values" do expect(request[:verb]).to eq(:get)
expect(path).to eq('/blogs/1/comments/2') expect(request[:path]).to eq('/blogs')
end
context "'path' parameters" do
before do
metadata[:path_item][:template] = '/blogs/{blog_id}/comments/{id}'
metadata[:operation][:parameters] = [
{ name: 'blog_id', in: :path, type: :number },
{ name: 'id', in: :path, type: :number }
]
allow(example).to receive(:blog_id).and_return(1)
allow(example).to receive(:id).and_return(2)
end
it 'builds the path from example values' do
expect(request[:path]).to eq('/blogs/1/comments/2')
end end
end end
context "'query' parameters" do context "'query' parameters" do
before do before do
api_metadata[:operation][:parameters] << { name: 'q1', in: :query, type: 'string' } metadata[:operation][:parameters] = [
api_metadata[:operation][:parameters] << { name: 'q2', in: :query, type: 'string' } { name: 'q1', in: :query, type: :string },
{ name: 'q2', in: :query, type: :string }
]
allow(example).to receive(:q1).and_return('foo') allow(example).to receive(:q1).and_return('foo')
allow(example).to receive(:q2).and_return('bar') allow(example).to receive(:q2).and_return('bar')
end end
it "appends a query string using metadata and example values" do it 'builds the query string from example values' do
expect(path).to eq('/blogs/1/comments/2?q1=foo&q2=bar') expect(request[:path]).to eq('/blogs?q1=foo&q2=bar')
end end
end end
context "optional 'query' parameters" do context "'query' parameters of type 'array'" do
before do before do
api_metadata[:operation][:parameters] << { name: 'q1', in: :query, type: 'string' } metadata[:operation][:parameters] = [
api_metadata[:operation][:parameters] << { name: 'q2', in: :query, type: 'string', required: true } { name: 'things', in: :query, type: :array, collectionFormat: collection_format }
api_metadata[:operation][:parameters] << { name: 'q3', in: :query, type: 'string', required: false } ]
api_metadata[:operation][:parameters] << { name: 'q4', in: :query, type: 'string', required: false } allow(example).to receive(:things).and_return(['foo', 'bar'])
allow(example).to receive(:q1).and_return('foo')
allow(example).to receive(:q2).and_return('bar')
allow(example).to receive(:q3).and_return('baz')
end
it "appends a query string using metadata and example values" do
expect(path).to eq('/blogs/1/comments/2?q1=foo&q2=bar&q3=baz')
end
end
context "'query' parameter of type 'array'" do
before do
api_metadata[:operation][:parameters] << {
name: 'things',
in: :query,
type: :array,
collectionFormat: collectionFormat
}
allow(example).to receive(:things).and_return([ 'foo', 'bar' ])
end end
context 'collectionFormat = csv' do context 'collectionFormat = csv' do
let(:collectionFormat) { :csv } let(:collection_format) { :csv }
it "formats as comma separated values" do it 'formats as comma separated values' do
expect(path).to eq('/blogs/1/comments/2?things=foo,bar') expect(request[:path]).to eq('/blogs?things=foo,bar')
end end
end end
context 'collectionFormat = ssv' do context 'collectionFormat = ssv' do
let(:collectionFormat) { :ssv } let(:collection_format) { :ssv }
it "formats as space separated values" do it 'formats as space separated values' do
expect(path).to eq('/blogs/1/comments/2?things=foo bar') expect(request[:path]).to eq('/blogs?things=foo bar')
end end
end end
context 'collectionFormat = tsv' do context 'collectionFormat = tsv' do
let(:collectionFormat) { :tsv } let(:collection_format) { :tsv }
it "formats as tab separated values" do it 'formats as tab separated values' do
expect(path).to eq('/blogs/1/comments/2?things=foo\tbar') expect(request[:path]).to eq('/blogs?things=foo\tbar')
end end
end end
context 'collectionFormat = pipes' do context 'collectionFormat = pipes' do
let(:collectionFormat) { :pipes } let(:collection_format) { :pipes }
it "formats as pipe separated values" do it 'formats as pipe separated values' do
expect(path).to eq('/blogs/1/comments/2?things=foo|bar') expect(request[:path]).to eq('/blogs?things=foo|bar')
end end
end end
context 'collectionFormat = multi' do context 'collectionFormat = multi' do
let(:collectionFormat) { :multi } let(:collection_format) { :multi }
it "formats as multiple parameter instances" do it 'formats as multiple parameter instances' do
expect(path).to eq('/blogs/1/comments/2?things=foo&things=bar') expect(request[:path]).to eq('/blogs?things=foo&things=bar')
end end
end end
end end
context "global definition for 'api_key in query'" do context "'header' parameters" do
before do before do
global_metadata[:securityDefinitions] = { api_key: { type: :apiKey, name: 'api_key', in: :query } } metadata[:operation][:parameters] = [{ name: 'Api-Key', in: :header, type: :string }]
allow(example).to receive(:api_key).and_return('fookey') allow(example).to receive(:'Api-Key').and_return('foobar')
end end
context 'global requirement' do it 'adds names and example values to headers' do
before { global_metadata[:security] = [ { api_key: [] } ] } expect(request[:headers]).to eq({ 'Api-Key' => 'foobar' })
end
end
it "appends the api_key using metadata and example value" do context 'optional parameters not provided' do
expect(path).to eq('/blogs/1/comments/2?api_key=fookey') before do
metadata[:operation][:parameters] = [
{ name: 'q1', in: :query, type: :string, required: false },
{ name: 'Api-Key', in: :header, type: :string, required: false }
]
end
it 'builds request hash without them' do
expect(request[:path]).to eq('/blogs')
expect(request[:headers]).to eq({})
end
end
context 'consumes content' do
before do
metadata[:operation][:consumes] = ['application/json', 'application/xml']
end
context "no 'Content-Type' provided" do
it "sets 'CONTENT_TYPE' header to first in list" do
expect(request[:headers]).to eq('CONTENT_TYPE' => 'application/json')
end end
end end
context 'operation-specific requirement' do context "explicit 'Content-Type' provided" do
before { api_metadata[:operation][:security] = [ { api_key: [] } ] } before do
allow(example).to receive(:'Content-Type').and_return('application/xml')
end
it "appends the api_key using metadata and example value" do it "sets 'CONTENT_TYPE' header to example value" do
expect(path).to eq('/blogs/1/comments/2?api_key=fookey') expect(request[:headers]).to eq('CONTENT_TYPE' => 'application/xml')
end
end
context 'JSON payload' do
before do
metadata[:operation][:parameters] = [{ name: 'comment', in: :body, schema: { type: 'object' } }]
allow(example).to receive(:comment).and_return(text: 'Some comment')
end
it "serializes first 'body' parameter to JSON string" do
expect(request[:payload]).to eq('{"text":"Some comment"}')
end
end
context 'missing body parameter' do
before do
metadata[:operation][:parameters] = [{ name: 'comment', in: :body, schema: { type: 'object' } }]
allow(example).to receive(:comment).and_raise(NoMethodError, "undefined method 'comment'")
allow(example).to receive(:respond_to?).with(:'Content-Type')
allow(example).to receive(:respond_to?).with('comment').and_return(false)
end
it 'uses the referenced metadata to build the request' do
expect do
request[:payload]
end.to raise_error(Rswag::Specs::MissingParameterError, /Missing parameter 'comment'/)
end
end
context 'form payload' do
before do
metadata[:operation][:consumes] = ['multipart/form-data']
metadata[:operation][:parameters] = [
{ name: 'f1', in: :formData, type: :string },
{ name: 'f2', in: :formData, type: :string }
]
allow(example).to receive(:f1).and_return('foo blah')
allow(example).to receive(:f2).and_return('bar blah')
end
it 'sets payload to hash of names and example values' do
expect(request[:payload]).to eq(
'f1' => 'foo blah',
'f2' => 'bar blah'
)
end
end
end
context 'produces content' do
before do
metadata[:operation][:produces] = ['application/json', 'application/xml']
end
context "no 'Accept' value provided" do
it "sets 'HTTP_ACCEPT' header to first in list" do
expect(request[:headers]).to eq('HTTP_ACCEPT' => 'application/json')
end
end
context "explicit 'Accept' value provided" do
before do
allow(example).to receive(:Accept).and_return('application/xml')
end
it "sets 'HTTP_ACCEPT' header to example value" do
expect(request[:headers]).to eq('HTTP_ACCEPT' => 'application/xml')
end
end
end
context 'basic auth' do
context 'swagger 2.0' do
before do
swagger_doc[:securityDefinitions] = { basic: { type: :basic } }
metadata[:operation][:security] = [basic: []]
allow(example).to receive(:Authorization).and_return('Basic foobar')
end
it "sets 'HTTP_AUTHORIZATION' header to example value" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
end
end
context 'openapi 3.0.1' do
let(:swagger_doc) { { openapi: '3.0.1' } }
before do
swagger_doc[:components] = { securitySchemes: { basic: { type: :basic } } }
metadata[:operation][:security] = [basic: []]
allow(example).to receive(:Authorization).and_return('Basic foobar')
end
it "sets 'HTTP_AUTHORIZATION' header to example value" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
end
end
context 'openapi 3.0.1 upgrade notice' do
let(:swagger_doc) { { openapi: '3.0.1' } }
before do
allow(ActiveSupport::Deprecation).to receive(:warn)
swagger_doc[:securityDefinitions] = { basic: { type: :basic } }
metadata[:operation][:security] = [basic: []]
allow(example).to receive(:Authorization).and_return('Basic foobar')
end
it 'warns the user to upgrade' do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
expect(ActiveSupport::Deprecation).to have_received(:warn)
.with('Rswag::Specs: WARNING: securityDefinitions is replaced in OpenAPI3! Rename to components/securitySchemes (in swagger_helper.rb)')
expect(swagger_doc[:components]).to have_key(:securitySchemes)
end
end
end
context 'apiKey' do
before do
swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: key_location } }
metadata[:operation][:security] = [apiKey: []]
allow(example).to receive(:api_key).and_return('foobar')
end
context 'in query' do
let(:key_location) { :query }
it 'adds name and example value to the query string' do
expect(request[:path]).to eq('/blogs?api_key=foobar')
end
end
context 'in header' do
let(:key_location) { :header }
it 'adds name and example value to the headers' do
expect(request[:headers]).to eq('api_key' => 'foobar')
end
end
context 'in header with auth param already added' do
let(:key_location) { :header }
before do
metadata[:operation][:parameters] = [
{ name: 'q1', in: :query, type: :string },
{ name: 'api_key', in: :header, type: :string }
]
allow(example).to receive(:q1).and_return('foo')
allow(example).to receive(:api_key).and_return('foobar')
end
it 'adds authorization parameter only once' do
expect(request[:headers]).to eq('api_key' => 'foobar')
expect(metadata[:operation][:parameters].size).to eq 2
end
end
end
context 'oauth2' do
before do
swagger_doc[:securityDefinitions] = { oauth2: { type: :oauth2, scopes: ['read:blogs'] } }
metadata[:operation][:security] = [oauth2: ['read:blogs']]
allow(example).to receive(:Authorization).and_return('Bearer foobar')
end
it "sets 'HTTP_AUTHORIZATION' header to example value" do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Bearer foobar')
end
end
context 'paired security requirements' do
before do
swagger_doc[:securityDefinitions] = {
basic: { type: :basic },
api_key: { type: :apiKey, name: 'api_key', in: :query }
}
metadata[:operation][:security] = [{ basic: [], api_key: [] }]
allow(example).to receive(:Authorization).and_return('Basic foobar')
allow(example).to receive(:api_key).and_return('foobar')
end
it 'sets both params to example values' do
expect(request[:headers]).to eq('HTTP_AUTHORIZATION' => 'Basic foobar')
expect(request[:path]).to eq('/blogs?api_key=foobar')
end
end
context 'path-level parameters' do
before do
metadata[:operation][:parameters] = [{ name: 'q1', in: :query, type: :string }]
metadata[:path_item][:parameters] = [{ name: 'q2', in: :query, type: :string }]
allow(example).to receive(:q1).and_return('foo')
allow(example).to receive(:q2).and_return('bar')
end
it 'populates operation and path level parameters' do
expect(request[:path]).to eq('/blogs?q1=foo&q2=bar')
end
end
context 'referenced parameters' do
context 'swagger 2.0' do
before do
swagger_doc[:parameters] = { q1: { name: 'q1', in: :query, type: :string } }
metadata[:operation][:parameters] = [{ '$ref' => '#/parameters/q1' }]
allow(example).to receive(:q1).and_return('foo')
end
it 'uses the referenced metadata to build the request' do
expect(request[:path]).to eq('/blogs?q1=foo')
end
end
context 'openapi 3.0.1' do
let(:swagger_doc) { { openapi: '3.0.1' } }
before do
swagger_doc[:components] = { parameters: { q1: { name: 'q1', in: :query, type: :string } } }
metadata[:operation][:parameters] = [{ '$ref' => '#/components/parameters/q1' }]
allow(example).to receive(:q1).and_return('foo')
end
it 'uses the referenced metadata to build the request' do
expect(request[:path]).to eq('/blogs?q1=foo')
end
end
context 'openapi 3.0.1 upgrade notice' do
let(:swagger_doc) { { openapi: '3.0.1' } }
before do
allow(ActiveSupport::Deprecation).to receive(:warn)
swagger_doc[:parameters] = { q1: { name: 'q1', in: :query, type: :string } }
metadata[:operation][:parameters] = [{ '$ref' => '#/parameters/q1' }]
allow(example).to receive(:q1).and_return('foo')
end
it 'warns the user to upgrade' do
expect(request[:path]).to eq('/blogs?q1=foo')
expect(ActiveSupport::Deprecation).to have_received(:warn)
.with('Rswag::Specs: WARNING: #/parameters/ refs are replaced in OpenAPI3! Rename to #/components/parameters/')
expect(ActiveSupport::Deprecation).to have_received(:warn)
.with('Rswag::Specs: WARNING: parameters is replaced in OpenAPI3! Rename to components/parameters (in swagger_helper.rb)')
end end
end end
end end
context 'global basePath' do context 'global basePath' do
before { global_metadata[:basePath] = '/foobar' } before { swagger_doc[:basePath] = '/api' }
it 'prepends the basePath' do it 'prepends to the path' do
expect(path).to eq('/foobar/blogs/1/comments/2') expect(request[:path]).to eq('/api/blogs')
end end
end end
context "defined at the 'path' level" do context 'global consumes' do
before { swagger_doc[:consumes] = ['application/xml'] }
it "defaults 'CONTENT_TYPE' to global value(s)" do
expect(request[:headers]).to eq('CONTENT_TYPE' => 'application/xml')
end
end
context 'global security requirements' do
before do before do
api_metadata[:path_item][:parameters] = [ { name: :blog_id, in: :path } ] swagger_doc[:securityDefinitions] = { apiKey: { type: :apiKey, name: 'api_key', in: :query } }
api_metadata[:operation][:parameters] = [ { name: :id, in: :path } ] swagger_doc[:security] = [apiKey: []]
allow(example).to receive(:api_key).and_return('foobar')
end end
it "builds path from parameters defined at path and operation levels" do it 'applieds the scheme by default' do
expect(path).to eq('/blogs/1/comments/2') expect(request[:path]).to eq('/blogs?api_key=foobar')
end
end
end
describe '#build_body(example)' do
let(:body) { subject.build_body(example) }
context "no 'body' parameter" do
it "returns ''" do
expect(body).to eq('')
end
end
context "'body' parameter" do
before do
api_metadata[:operation][:parameters] << { name: 'comment', in: :body, schema: { type: 'object' } }
allow(example).to receive(:comment).and_return(text: 'Some comment')
end
it 'returns the example value as a json string' do
expect(body).to eq("{\"text\":\"Some comment\"}")
end
end
context "referenced 'body' parameter" do
before do
api_metadata[:operation][:parameters] << { '$ref' => '#/parameters/comment' }
global_metadata[:parameters] = {
'comment' => { name: 'comment', in: :body, schema: { type: 'object' } }
}
allow(example).to receive(:comment).and_return(text: 'Some comment')
end
it 'returns the example value as a json string' do
expect(body).to eq("{\"text\":\"Some comment\"}")
end
end
end
describe '#build_headers' do
let(:headers) { subject.build_headers(example) }
context "no 'header' params" do
it 'returns an empty hash' do
expect(headers).to eq({})
end
end
context "'header' params" do
before do
api_metadata[:operation][:parameters] << { name: 'Api-Key', in: :header, type: 'string' }
allow(example).to receive(:'Api-Key').and_return('foobar')
end
it 'returns a hash of names with example values' do
expect(headers).to eq({ 'Api-Key' => 'foobar' })
end
end
context "global definition for 'basic auth'" do
before do
global_metadata[:securityDefinitions] = { basic_auth: { type: :basic} }
allow(example).to receive(:'Authorization').and_return('Basic foobar')
end
context 'global requirement' do
before { global_metadata[:security] = [ { basic_auth: [] } ] }
it "includes a corresponding Authorization header" do
expect(headers).to match(
'Authorization' => 'Basic foobar'
)
end
end
context 'operation-specific requirement' do
before { api_metadata[:operation][:security] = [ { basic_auth: [] } ] }
it "includes a corresponding Authorization header" do
expect(headers).to match(
'Authorization' => 'Basic foobar'
)
end
end
end
context 'consumes & produces' do
before do
api_metadata[:operation][:consumes] = [ 'application/json', 'application/xml' ]
api_metadata[:operation][:produces] = [ 'application/json', 'application/xml' ]
end
it "includes corresponding 'Accept' & 'Content-Type' headers" do
expect(headers).to match(
'Accept' => 'application/json;application/xml',
'Content-Type' => 'application/json;application/xml'
)
end
end
context 'global consumes & produces' do
let(:global_metadata) do
{
consumes: [ 'application/json', 'application/xml' ],
produces: [ 'application/json', 'application/xml' ]
}
end
it "includes corresponding 'Accept' & 'Content-Type' headers" do
expect(headers).to match(
'Accept' => 'application/json;application/xml',
'Content-Type' => 'application/json;application/xml'
)
end end
end end
end end

View File

@ -1,124 +1,122 @@
# frozen_string_literal: true
require 'rswag/specs/response_validator' require 'rswag/specs/response_validator'
module Rswag module Rswag
module Specs module Specs
RSpec.describe ResponseValidator do
subject { ResponseValidator.new(config) }
describe ResponseValidator do before do
subject { ResponseValidator.new(api_metadata, global_metadata) } allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
allow(config).to receive(:get_swagger_doc_version).and_return('2.0')
let(:api_metadata) { { response: { code: 200 } } } end
let(:global_metadata) { {} } let(:config) { double('config') }
let(:swagger_doc) { {} }
describe '#validate!(response)' do let(:example) { double('example') }
let(:call) { subject.validate!(response) } let(:metadata) do
{
context "no 'schema' provided" do response: {
context 'response code matches' do code: 200,
let(:response) { OpenStruct.new(code: 200, body: '') } headers: { 'X-Rate-Limit-Limit' => { type: :integer } },
it { expect { call }.to_not raise_error } schema: {
end type: :object,
properties: { text: { type: :string } },
context 'response code does not match' do
let(:response) { OpenStruct.new(code: 201, body: '') }
it { expect { call }.to raise_error UnexpectedResponse }
end
end
context "'schema' provided" do
before do
api_metadata[:response][:schema] = {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text'] required: ['text']
} }
}
}
end
describe '#validate!(metadata, response)' do
let(:call) { subject.validate!(metadata, response) }
let(:response) do
OpenStruct.new(
code: '200',
headers: { 'X-Rate-Limit-Limit' => '10' },
body: '{"text":"Some comment"}'
)
end
context 'response matches metadata' do
it { expect { call }.to_not raise_error }
end
context 'response code differs from metadata' do
before { response.code = '400' }
it { expect { call }.to raise_error(/Expected response code/) }
end
context 'response headers differ from metadata' do
before { response.headers = {} }
it { expect { call }.to raise_error(/Expected response header/) }
end
context 'response body differs from metadata' do
before { response.body = '{"foo":"Some comment"}' }
it { expect { call }.to raise_error(/Expected response body/) }
end
context 'referenced schemas' do
context 'swagger 2.0' do
before do
swagger_doc[:definitions] = {
'blog' => {
type: :object,
properties: { foo: { type: :string } },
required: ['foo']
}
}
metadata[:response][:schema] = { '$ref' => '#/definitions/blog' }
end
it 'uses the referenced schema to validate the response body' do
expect { call }.to raise_error(/Expected response body/)
end
end end
context 'response code & body matches' do context 'openapi 3.0.1' do
let(:response) { OpenStruct.new(code: 200, body: "{\"text\":\"Some comment\"}") } context 'components/schemas' do
it { expect { call }.to_not raise_error } before do
end allow(ActiveSupport::Deprecation).to receive(:warn)
allow(config).to receive(:get_swagger_doc_version).and_return('3.0.1')
swagger_doc[:components] = {
schemas: {
'blog' => {
type: :object,
properties: { foo: { type: :string } },
required: ['foo']
}
}
}
metadata[:response][:schema] = { '$ref' => '#/components/schemas/blog' }
end
context 'response code matches & body does not' do it 'uses the referenced schema to validate the response body' do
let(:response) { OpenStruct.new(code: 200, body: "{\"foo\":\"Some comment\"}") } expect { call }.to raise_error(/Expected response body/)
it { expect { call }.to raise_error UnexpectedResponse }
end
context "'block' provided" do
let(:call) do
subject.validate!(response) do |response|
data = JSON.parse(response.body)
expect(data['text']).to eq('Some comment')
end end
end end
context 'the block validation passes' do context 'deprecated definitions' do
let(:response) { OpenStruct.new(code: 200, body: "{\"text\":\"Some comment\"}") } before do
it { expect { call }.to_not raise_error } allow(ActiveSupport::Deprecation).to receive(:warn)
allow(config).to receive(:get_swagger_doc_version).and_return('3.0.1')
swagger_doc[:definitions] = {
'blog' => {
type: :object,
properties: { foo: { type: :string } },
required: ['foo']
}
}
metadata[:response][:schema] = { '$ref' => '#/definitions/blog' }
end
it 'warns the user to upgrade' do
expect { call }.to raise_error(/Expected response body/)
expect(ActiveSupport::Deprecation).to have_received(:warn)
.with('Rswag::Specs: WARNING: definitions is replaced in OpenAPI3! Rename to components/schemas (in swagger_helper.rb)')
end
end end
context 'the block validation fails' do
let(:response) { OpenStruct.new(code: 200, body: "{\"text\":\"Some other comment\"}") }
it { expect { call }.to raise_error(RSpec::Expectations::ExpectationNotMetError) }
end
end
end
context "referenced 'schema' provided" do
before do
api_metadata[:response][:schema] = { '$ref' => '#/definitions/author' }
global_metadata[:definitions] = {
author: {
type: 'object',
properties: { name: { type: 'string' } },
required: ['name']
}
}
end
context 'response code & body matches' do
let(:response) { OpenStruct.new(code: 200, body: "{\"name\":\"Some name\"}") }
it { expect { call }.to_not raise_error }
end
context 'response code matches & body does not' do
let(:response) { OpenStruct.new(code: 200, body: "{\"foo\":\"Some name\"}") }
it { expect { call }.to raise_error UnexpectedResponse }
end
end
context "'headers' provided" do
before do
api_metadata[:response][:headers] = {
'X-Rate-Limit-Limit' => {
description: 'The number of allowed requests in the current period',
type: 'integer'
},
'X-Rate-Limit-Remaining' => {
description: 'The number of remaining requests in the current period',
type: 'integer'
},
'X-Rate-Limit-Reset' => {
description: 'The number of seconds left in the current period',
type: 'integer'
}
}
end
context 'response code & body matches' do
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
'X-Rate-Limit-Limit' => 1,
'X-Rate-Limit-Remaining' => 1,
'X-Rate-Limit-Reset' => 1
}) }
it { expect { call }.to_not raise_error }
end
context 'response code matches & body does not' do
let(:response) { OpenStruct.new(code: 200, body: '{}', headers: {
'X-Rate-Limit-Limit' => 1,
'X-Rate-Limit-Remaining' => 1
}) }
it { expect { call }.to raise_error UnexpectedResponse }
end end
end end
end end

View File

@ -1,70 +1,375 @@
# frozen_string_literal: true
require 'rswag/specs/swagger_formatter' require 'rswag/specs/swagger_formatter'
require 'ostruct' require 'ostruct'
module Rswag module Rswag
module Specs module Specs
RSpec.describe SwaggerFormatter do
describe SwaggerFormatter do
subject { described_class.new(output, config) } subject { described_class.new(output, config) }
# Mock out some infrastructure # Mock out some infrastructure
before do before do
allow(config).to receive(:swagger_root).and_return(swagger_root) allow(config).to receive(:swagger_root).and_return(swagger_root)
allow(ActiveSupport::Deprecation).to receive(:warn) # Silence deprecation output from specs
end end
let(:config) { double('config') } let(:config) { double('config') }
let(:output) { double('output').as_null_object } let(:output) { double('output').as_null_object }
let(:swagger_root) { File.expand_path('../tmp/swagger', __FILE__) } let(:swagger_root) { File.expand_path('tmp/swagger', __dir__) }
describe '#example_group_finished(notification)' do describe '#example_group_finished(notification)' do
before do before do
allow(config).to receive(:get_swagger_doc).and_return(swagger_doc) allow(config).to receive(:get_swagger_doc).and_return(swagger_doc)
subject.example_group_finished(notification) subject.example_group_finished(notification)
end end
let(:swagger_doc) { {} }
let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) } let(:notification) { OpenStruct.new(group: OpenStruct.new(metadata: api_metadata)) }
let(:api_metadata) do let(:api_metadata) do
{ {
path_item: { template: '/blogs' }, path_item: { template: '/blogs', parameters: [{ type: :string }] },
operation: { verb: :post, summary: 'Creates a blog' }, operation: { verb: :post, summary: 'Creates a blog', parameters: [{ type: :string }] },
response: { code: '201', description: 'blog created' } response: response_metadata,
document: document
} }
end end
let(:response_metadata) { { code: '201', description: 'blog created', headers: { type: :string }, schema: { '$ref' => '#/definitions/blog' } } }
it 'converts to swagger and merges into the corresponding swagger doc' do context 'with the document tag set to false' do
expect(swagger_doc).to match( let(:swagger_doc) { { swagger: '2.0' } }
paths: { let(:document) { false }
'/blogs' => {
post: { it 'does not update the swagger doc' do
summary: 'Creates a blog', expect(swagger_doc).to match({ swagger: '2.0' })
responses: { end
'201' => { description: 'blog created' } end
context 'with the document tag set to anything but false' do
let(:swagger_doc) { { swagger: '2.0' } }
# anything works, including its absence when specifying responses.
let(:document) { nil }
it 'converts to swagger and merges into the corresponding swagger doc' do
expect(swagger_doc).to match(
swagger: '2.0',
paths: {
'/blogs' => {
parameters: [{ type: :string }],
post: {
parameters: [{ type: :string }],
summary: 'Creates a blog',
responses: {
'201' => {
description: 'blog created',
headers: { type: :string },
schema: { '$ref' => '#/definitions/blog' }
}
}
}
}
}
)
end
end
context 'with metadata upgrades for 3.0' do
let(:swagger_doc) do
{
openapi: '3.0.1',
basePath: '/foo',
schemes: ['http', 'https'],
host: 'api.example.com',
produces: ['application/vnd.my_mime', 'application/json'],
components: {
securitySchemes: {
myClientCredentials: {
type: :oauth2,
flow: :application,
token_url: :somewhere
},
myAuthorizationCode: {
type: :oauth2,
flow: :accessCode,
token_url: :somewhere
},
myImplicit: {
type: :oauth2,
flow: :implicit,
token_url: :somewhere
} }
} }
} }
} }
) end
let(:document) { nil }
it 'converts query and path params, type: to schema: { type: }' do
expect(swagger_doc.slice(:paths)).to match(
paths: {
'/blogs' => {
parameters: [{ schema: { type: :string } }],
post: {
parameters: [{ schema: { type: :string } }],
summary: 'Creates a blog',
responses: {
'201' => {
content: {
'application/vnd.my_mime' => {
schema: { '$ref' => '#/definitions/blog' }
},
'application/json' => {
schema: { '$ref' => '#/definitions/blog' }
}
},
description: 'blog created',
headers: { schema: { type: :string } }
}
}
}
}
}
)
end
context 'with response example' do
let(:response_metadata) do
{
code: '201',
description: 'blog created',
headers: { type: :string },
content: { 'application/json' => { example: { foo: :bar } } },
schema: { '$ref' => '#/definitions/blog' }
}
end
it 'adds example to definition' do
expect(swagger_doc.slice(:paths)).to match(
paths: {
'/blogs' => {
parameters: [{ schema: { type: :string } }],
post: {
parameters: [{ schema: { type: :string } }],
summary: 'Creates a blog',
responses: {
'201' => {
content: {
'application/vnd.my_mime' => {
schema: { '$ref' => '#/definitions/blog' }
},
'application/json' => {
schema: { '$ref' => '#/definitions/blog' },
example: { foo: :bar }
}
},
description: 'blog created',
headers: { schema: { type: :string } }
}
}
}
}
}
)
end
end
context 'with empty content' do
let(:swagger_doc) do
{
openapi: '3.0.1',
basePath: '/foo',
schemes: ['http', 'https'],
host: 'api.example.com',
components: {
securitySchemes: {
myClientCredentials: {
type: :oauth2,
flow: :application,
token_url: :somewhere
},
myAuthorizationCode: {
type: :oauth2,
flow: :accessCode,
token_url: :somewhere
},
myImplicit: {
type: :oauth2,
flow: :implicit,
token_url: :somewhere
}
}
}
}
end
it 'converts query and path params, type: to schema: { type: }' do
expect(swagger_doc.slice(:paths)).to match(
paths: {
'/blogs' => {
parameters: [{ schema: { type: :string } }],
post: {
parameters: [{ schema: { type: :string } }],
summary: 'Creates a blog',
responses: {
'201' => {
description: 'blog created',
headers: { schema: { type: :string } }
}
}
}
}
}
)
end
end
it 'converts basePath, schemas and host to urls' do
expect(swagger_doc.slice(:servers)).to match(
servers: {
urls: ['http://api.example.com/foo', 'https://api.example.com/foo']
}
)
end
it 'upgrades oauth flow to flows' do
expect(swagger_doc.slice(:components)).to match(
components: {
securitySchemes: {
myClientCredentials: {
type: :oauth2,
flows: {
'clientCredentials' => {
token_url: :somewhere
}
}
},
myAuthorizationCode: {
type: :oauth2,
flows: {
'authorizationCode' => {
token_url: :somewhere
}
}
},
myImplicit: {
type: :oauth2,
flows: {
'implicit' => {
token_url: :somewhere
}
}
}
}
}
)
end
end end
end end
describe '#stop' do describe '#stop' do
before do before do
FileUtils.rm_r(swagger_root) if File.exists?(swagger_root) FileUtils.rm_r(swagger_root) if File.exist?(swagger_root)
allow(config).to receive(:swagger_docs).and_return( allow(config).to receive(:swagger_docs).and_return(
'v1/swagger.json' => { info: { version: 'v1' } }, 'v1/swagger.json' => doc_1,
'v2/swagger.json' => { info: { version: 'v2' } } 'v2/swagger.json' => doc_2
) )
allow(config).to receive(:swagger_format).and_return(swagger_format)
subject.stop(notification) subject.stop(notification)
end end
let(:notification) { double('notification') } let(:doc_1) { { info: { version: 'v1' } } }
let(:doc_2) { { info: { version: 'v2' } } }
let(:swagger_format) { :json }
it 'writes the swagger_doc(s) to file' do let(:notification) { double('notification') }
expect(File).to exist("#{swagger_root}/v1/swagger.json") context 'with default format' do
expect(File).to exist("#{swagger_root}/v2/swagger.json") it 'writes the swagger_doc(s) to file' do
expect(File).to exist("#{swagger_root}/v1/swagger.json")
expect(File).to exist("#{swagger_root}/v2/swagger.json")
expect { JSON.parse(File.read("#{swagger_root}/v2/swagger.json")) }.not_to raise_error
end
end
context 'with yaml format' do
let(:swagger_format) { :yaml }
it 'writes the swagger_doc(s) as yaml' do
expect(File).to exist("#{swagger_root}/v1/swagger.json")
expect { JSON.parse(File.read("#{swagger_root}/v1/swagger.json")) }.to raise_error(JSON::ParserError)
# Psych::DisallowedClass would be raised if we do not pre-process ruby symbols
expect { YAML.safe_load(File.read("#{swagger_root}/v1/swagger.json")) }.not_to raise_error
end
end
context 'with oauth3 upgrades' do
let(:doc_2) do
{
paths: {
'/path/' => {
get: {
summary: 'Retrieve Nested Paths',
tags: ['nested Paths'],
produces: ['application/json'],
consumes: ['application/xml', 'application/json'],
parameters: [{
in: :body,
schema: { foo: :bar }
}, {
in: :headers
}]
}
}
}
}
end
it 'removes remaining consumes/produces' do
expect(doc_2[:paths]['/path/'][:get].keys).to eql([:summary, :tags, :parameters, :requestBody])
end
it 'duplicates params in: :body to requestBody from consumes list' do
expect(doc_2[:paths]['/path/'][:get][:parameters]).to eql([{ in: :headers }])
expect(doc_2[:paths]['/path/'][:get][:requestBody]).to eql(content: {
'application/xml' => { schema: { foo: :bar } },
'application/json' => { schema: { foo: :bar } }
})
end
end
context 'with oauth3 formData' do
let(:doc_2) do
{
paths: {
'/path/' => {
post: {
summary: 'Retrieve Nested Paths',
tags: ['nested Paths'],
produces: ['application/json'],
consumes: ['multipart/form-data'],
parameters: [{
in: :formData,
schema: { type: :file }
},{
in: :headers
}]
}
}
}
}
end
it 'removes remaining consumes/produces' do
expect(doc_2[:paths]['/path/'][:post].keys).to eql([:summary, :tags, :parameters, :requestBody])
end
it 'duplicates params in: :formData to requestBody from consumes list' do
expect(doc_2[:paths]['/path/'][:post][:parameters]).to eql([{ in: :headers }])
expect(doc_2[:paths]['/path/'][:post][:requestBody]).to eql(content: {
'multipart/form-data' => { schema: { type: :file } }
})
end
end end
after do after do
FileUtils.rm_r(swagger_root) if File.exists?(swagger_root) FileUtils.rm_r(swagger_root) if File.exist?(swagger_root)
end end
end end
end end

View File

@ -1,3 +1,5 @@
# frozen_string_literal: true
module Rails module Rails
module VERSION module VERSION
MAJOR = 3 MAJOR = 3

View File

@ -1,2 +1,4 @@
# frozen_string_literal: true
# NOTE: For the specs in this gem, all configuration is completely mocked out # NOTE: For the specs in this gem, all configuration is completely mocked out
# The file just needs to be present because it gets required by the swagger_formatter # The file just needs to be present because it gets required by the swagger_formatter

View File

@ -1,11 +0,0 @@
module Rswag
module Ui
class HomeController < ActionController::Base
def index
@swagger_endpoints = Rswag::Ui.config.swagger_endpoints
render :index, layout: false
end
end
end
end

View File

@ -1,126 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="icon" type="image/png" href="<%= asset_path 'swagger-ui/images/favicon-32x32.png' %>" sizes="32x32" />
<link rel="icon" type="image/png" href="<%= asset_path 'swagger-ui/images/favicon-16x16.png' %>" sizes="16x16" />
<link href="<%= asset_path 'swagger-ui/css/typography.css' %>" media='screen' rel='stylesheet' type='text/css'/>
<link href="<%= asset_path 'swagger-ui/css/reset.css' %>" media='screen' rel='stylesheet' type='text/css'/>
<link href="<%= asset_path 'swagger-ui/css/screen.css' %>" media='screen' rel='stylesheet' type='text/css'/>
<link href="<%= asset_path 'swagger-ui/css/reset.css' %>" media='print' rel='stylesheet' type='text/css'/>
<link href="<%= asset_path 'swagger-ui/css/print.css' %>" media='print' rel='stylesheet' type='text/css'/>
<script src="<%= asset_path 'swagger-ui/lib/object-assign-pollyfill.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/jquery-1.8.0.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/jquery.slideto.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/jquery.wiggle.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/jquery.ba-bbq.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/handlebars-4.0.5.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/lodash.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/backbone-min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/swagger-ui.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/highlight.9.1.0.pack.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/highlight.9.1.0.pack_extended.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/jsoneditor.min.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/marked.js' %>" type='text/javascript'></script>
<script src="<%= asset_path 'swagger-ui/lib/swagger-oauth.js' %>" type='text/javascript'></script>
<!-- Some basic translations -->
<!-- <script src="<%= asset_path 'swagger-ui/lang/translator.js' %>" type='text/javascript'></script> -->
<!-- <script src="<%= asset_path 'swagger-ui/lang/ru.js' %>" type='text/javascript'></script> -->
<!-- <script src="<%= asset_path 'swagger-ui/lang/en.js' %>" type='text/javascript'></script> -->
<script type="text/javascript">
$(function () {
hljs.configure({
highlightSizeThreshold: 5000
});
// Pre load translate...
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
window.swaggerUi = new SwaggerUi({
url: '<%= @swagger_endpoints.first.path %>',
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
onComplete: function(swaggerApi, swaggerUi){
if(typeof initOAuth == "function") {
initOAuth({
clientId: "your-client-id",
clientSecret: "your-client-secret-if-required",
realm: "your-realms",
appName: "your-app-name",
scopeSeparator: " ",
additionalQueryStringParams: {}
});
}
if(window.SwaggerTranslator) {
window.SwaggerTranslator.translate();
}
},
onFailure: function(data) {
log("Unable to Load SwaggerUI");
},
docExpansion: "list",
jsonEditor: false,
defaultModelRendering: 'schema',
showRequestHeaders: false
});
window.swaggerUi.load();
function log() {
if ('console' in window) {
console.log.apply(console, arguments);
}
}
});
</script>
</head>
<body class="swagger-section">
<div id='header'>
<div class="swagger-ui-wrap">
<a id="logo" href="http://swagger.io"><img class="logo__img" alt="swagger" height="30" width="30" src="<%= asset_path 'swagger-ui/images/logo_small.png' %>" /><span class="logo__title">swagger</span></a>
<form id='api_selector'>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
<div id='auth_container'></div>
<select id="select_document">
<% @swagger_endpoints.each do |endpoint| %>
<option value='<%= endpoint.path %>'><%= endpoint.title %></option>
<% end %>
</select>
<script type="text/javascript">
// Refresh the swagger-ui when a new document is selected
$('#select_document').change(function () {
$('#input_baseUrl').val($(this).val());
window.swaggerUi.headerView.showCustom();
});
</script>
<style>
#select_document {
border: none;
height: 1.85em;
border-radius: 4px;
-moz-border-radius: 4px;
-webkit-border-radius: 4px;
-o-border-radius: 4px;
-ms-border-radius: 4px;
-khtml-border-radius: 4px;
font-size: 0.85em;
font-weight: bold;
color: white;
background-color: #547f00;
}
</style>
</form>
</div>
</div>
<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
</html>

View File

@ -1,3 +0,0 @@
Rswag::Ui::Engine.routes.draw do
root to: 'home#index'
end

View File

@ -3,10 +3,10 @@ require 'rails/generators'
module Rswag module Rswag
module Ui module Ui
class CustomGenerator < Rails::Generators::Base class CustomGenerator < Rails::Generators::Base
source_root File.expand_path('../../../../../../app/views/rswag/ui/home', __FILE__) source_root File.expand_path('../../../../../../lib/rswag/ui', __FILE__)
def add_custom_index def add_custom_index
copy_file('index.html.erb', 'app/views/rswag/ui/home/index.html.erb') copy_file('index.erb', 'app/views/rswag/ui/home/index.html.erb')
end end
end end
end end

View File

@ -2,8 +2,13 @@ Rswag::Ui.configure do |c|
# List the Swagger endpoints that you want to be documented through the swagger-ui # List the Swagger endpoints that you want to be documented through the swagger-ui
# The first parameter is the path (absolute or relative to the UI host) to the corresponding # The first parameter is the path (absolute or relative to the UI host) to the corresponding
# JSON endpoint and the second is a title that will be displayed in the document selector # endpoint and the second is a title that will be displayed in the document selector
# NOTE: If you're using rspec-api to expose Swagger files (under swagger_root) as JSON endpoints, # NOTE: If you're using rspec-api to expose Swagger files (under swagger_root) as JSON or YAML endpoints,
# then the list below should correspond to the relative paths for those endpoints # then the list below should correspond to the relative paths for those endpoints
c.swagger_endpoint '/api-docs/v1/swagger.json', 'API V1 Docs'
c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs'
# Add Basic Auth in case your API is private
# c.basic_auth_enabled = true
# c.basic_auth_credentials 'username', 'password'
end end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
require 'rack/auth/basic'
module Rswag
module Ui
# Extend Rack HTTP Basic Authentication, as per RFC 2617.
# @api private
#
class BasicAuth < ::Rack::Auth::Basic
def call(env)
return @app.call(env) unless env_matching_path(env)
super(env)
end
private
def env_matching_path(env)
path = base_path(env['PATH_INFO'])
Rswag::Ui.config.config_object[:urls].find do |endpoint|
base_path(endpoint[:url]) == path
end
end
def base_path(url)
url.downcase.split('/')[1]
end
end
end
end

View File

@ -1,17 +1,44 @@
require 'ostruct' require 'ostruct'
require 'rack'
module Rswag module Rswag
module Ui module Ui
class Configuration class Configuration
attr_reader :swagger_endpoints attr_reader :template_locations
attr_accessor :basic_auth_enabled
attr_accessor :config_object
attr_accessor :oauth_config_object
attr_reader :assets_root
def initialize def initialize
@swagger_endpoints = [] @template_locations = [
# preffered override location
"#{Rack::Directory.new('').root}/swagger/index.erb",
# backwards compatible override location
"#{Rack::Directory.new('').root}/app/views/rswag/ui/home/index.html.erb",
# default location
File.expand_path('../index.erb', __FILE__)
]
@assets_root = File.expand_path('../../../../node_modules/swagger-ui-dist', __FILE__)
@config_object = {}
@oauth_config_object = {}
@basic_auth_enabled = false
end end
def swagger_endpoint(path, title) def swagger_endpoint(url, name)
@swagger_endpoints << OpenStruct.new(path: path, title: title) @config_object[:urls] ||= []
@config_object[:urls] << { url: url, name: name }
end end
def basic_auth_credentials(username, password)
@config_object[:basic_auth] = { username: username, password: password }
end
# rubocop:disable Naming/AccessorMethodName
def get_binding
binding
end
# rubocop:enable Naming/AccessorMethodName
end end
end end
end end

View File

@ -1,20 +1,25 @@
require 'rswag/ui/middleware'
require 'rswag/ui/basic_auth'
module Rswag module Rswag
module Ui module Ui
class Engine < ::Rails::Engine class Engine < ::Rails::Engine
isolate_namespace Rswag::Ui isolate_namespace Rswag::Ui
initializer 'rswag-ui.initialize' do |app| initializer 'rswag-ui.initialize' do |app|
if app.config.respond_to?(:assets) middleware.use Rswag::Ui::Middleware, Rswag::Ui.config
app.config.assets.precompile += [
'swagger-ui/css/*', if Rswag::Ui.config.basic_auth_enabled
'swagger-ui/fonts/*', c = Rswag::Ui.config
'swagger-ui/images/*', app.middleware.use Rswag::Ui::BasicAuth do |username, password|
'swagger-ui/lang/*', c.config_object[:basic_auth].values == [username, password]
'swagger-ui/lib/*', end
'swagger-ui/swagger-ui.min.js'
]
end end
end end
rake_tasks do
load File.expand_path('../../../tasks/rswag-ui_tasks.rake', __FILE__)
end
end end
end end
end end

View File

@ -0,0 +1,103 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700|Source+Code+Pro:300,600|Titillium+Web:400,600,700" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>
html
{
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after
{
box-sizing: inherit;
}
body {
margin:0;
background: #fafafa;
}
</style>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position:absolute;width:0;height:0">
<defs>
<symbol viewBox="0 0 20 20" id="unlocked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V6h2v-.801C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8z"></path>
</symbol>
<symbol viewBox="0 0 20 20" id="locked">
<path d="M15.8 8H14V5.6C14 2.703 12.665 1 10 1 7.334 1 6 2.703 6 5.6V8H4c-.553 0-1 .646-1 1.199V17c0 .549.428 1.139.951 1.307l1.197.387C5.672 18.861 6.55 19 7.1 19h5.8c.549 0 1.428-.139 1.951-.307l1.196-.387c.524-.167.953-.757.953-1.306V9.199C17 8.646 16.352 8 15.8 8zM12 8H8V5.199C8 3.754 8.797 3 10 3c1.203 0 2 .754 2 2.199V8z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="close">
<path d="M14.348 14.849c-.469.469-1.229.469-1.697 0L10 11.819l-2.651 3.029c-.469.469-1.229.469-1.697 0-.469-.469-.469-1.229 0-1.697l2.758-3.15-2.759-3.152c-.469-.469-.469-1.228 0-1.697.469-.469 1.228-.469 1.697 0L10 8.183l2.651-3.031c.469-.469 1.228-.469 1.697 0 .469.469.469 1.229 0 1.697l-2.758 3.152 2.758 3.15c.469.469.469 1.229 0 1.698z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow">
<path d="M13.25 10L6.109 2.58c-.268-.27-.268-.707 0-.979.268-.27.701-.27.969 0l7.83 7.908c.268.271.268.709 0 .979l-7.83 7.908c-.268.271-.701.27-.969 0-.268-.269-.268-.707 0-.979L13.25 10z"/>
</symbol>
<symbol viewBox="0 0 20 20" id="large-arrow-down">
<path d="M17.418 6.109c.272-.268.709-.268.979 0s.271.701 0 .969l-7.908 7.83c-.27.268-.707.268-.979 0l-7.908-7.83c-.27-.268-.27-.701 0-.969.271-.268.709-.268.979 0L10 13.25l7.418-7.141z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="jump-to">
<path d="M19 7v4H5.83l3.58-3.59L8 6l-6 6 6 6 1.41-1.41L5.83 13H21V7z"/>
</symbol>
<symbol viewBox="0 0 24 24" id="expand">
<path d="M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z"/>
</symbol>
</defs>
</svg>
<div id="swagger-ui"></div>
<!-- Workaround for https://github.com/swagger-api/swagger-editor/issues/1371 -->
<script>
if (window.navigator.userAgent.indexOf("Edge") > -1) {
console.log("Removing native Edge fetch in favor of swagger-ui's polyfill")
window.fetch = undefined;
}
</script>
<script src="./swagger-ui-bundle.js"> </script>
<script src="./swagger-ui-standalone-preset.js"> </script>
<script>
window.onload = function () {
var configObject = JSON.parse('<%= config_object.to_json %>');
var oauthConfigObject = JSON.parse('<%= oauth_config_object.to_json %>');
// Apply mandatory parameters
configObject.dom_id = "#swagger-ui";
configObject.presets = [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset];
configObject.layout = "StandaloneLayout";
// If oauth2RedirectUrl isn't specified, use the built-in default
if (!configObject.hasOwnProperty("oauth2RedirectUrl"))
configObject.oauth2RedirectUrl = window.location.href.replace("index.html", "oauth2-redirect.html");
// Build a system
const ui = SwaggerUIBundle(configObject);
// Apply OAuth config
ui.initOAuth(oauthConfigObject);
}
</script>
</body>
</html>

View File

@ -0,0 +1,44 @@
module Rswag
module Ui
class Middleware < Rack::Static
def initialize(app, config)
@config = config
super(app, urls: [ '' ], root: config.assets_root )
end
def call(env)
if base_path?(env)
redirect_uri = env['SCRIPT_NAME'].chomp('/') + '/index.html'
return [ 301, { 'Location' => redirect_uri }, [ ] ]
end
if index_path?(env)
return [ 200, { 'Content-Type' => 'text/html' }, [ render_template ] ]
end
super
end
private
def base_path?(env)
env['REQUEST_METHOD'] == "GET" && env['PATH_INFO'] == "/"
end
def index_path?(env)
env['REQUEST_METHOD'] == "GET" && env['PATH_INFO'] == "/index.html"
end
def render_template
file = File.new(template_filename)
template = ERB.new(file.read)
template.result(@config.get_binding)
end
def template_filename
@config.template_locations.find { |filename| File.exists?(filename) }
end
end
end
end

View File

@ -0,0 +1,12 @@
namespace :rswag do
namespace :ui do
desc 'TODO'
task :copy_assets, [ :dest ] do |t, args|
dest = args[:dest]
FileUtils.rm_r(dest, force: true)
FileUtils.mkdir_p(dest)
FileUtils.cp_r(Dir.glob("#{Rswag::Ui.config.assets_root}/{*.js,*.png,*.css}"), dest)
end
end
end

13
rswag-ui/package-lock.json generated Normal file
View File

@ -0,0 +1,13 @@
{
"name": "rswag-ui",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"swagger-ui-dist": {
"version": "3.52.5",
"resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz",
"integrity": "sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw=="
}
}
}

8
rswag-ui/package.json Normal file
View File

@ -0,0 +1,8 @@
{
"name": "rswag-ui",
"version": "1.0.0",
"private": true,
"dependencies": {
"swagger-ui-dist": "3.52.5"
}
}

View File

@ -1,18 +1,20 @@
$:.push File.expand_path("../lib", __FILE__) # frozen_string_literal: true
$LOAD_PATH.push File.expand_path('../lib', __FILE__)
# Describe your gem and declare its dependencies: # Describe your gem and declare its dependencies:
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = "rswag-ui" s.name = 'rswag-ui'
s.version = ENV['TRAVIS_TAG'] || '0.0.0' s.version = ENV['TRAVIS_TAG'] || '0.0.0'
s.authors = ["Richie Morris"] s.authors = ['Richie Morris', 'Greg Myers', 'Jay Danielian']
s.email = ["domaindrivendev@gmail.com"] s.email = ['domaindrivendev@gmail.com']
s.homepage = "https://github.com/domaindrivendev/rswag" s.homepage = 'https://github.com/rswag/rswag'
s.summary = "A Rails Engine that includes swagger-ui and powers it from configured Swagger endpoints" s.summary = 'A Rails Engine that includes swagger-ui and powers it from configured OpenAPI (formerly named Swagger) endpoints'
s.description = "Expose beautiful API documentation, that's powered by Swagger JSON endpoints, including a UI to explore and test operations" s.description = 'Expose beautiful API documentation, powered by Swagger JSON endpoints, including a UI to explore and test operations. More about the OpenAPI initiative here: http://spec.openapis.org/'
s.license = "MIT" s.license = 'MIT'
s.files = Dir["{app,config,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile" ] s.files = Dir.glob('{lib,node_modules}/**/*') + ['MIT-LICENSE', 'Rakefile' ]
s.add_dependency 'actionpack', '>=3.1', '< 6.0' s.add_dependency 'actionpack', '>=3.1', '< 7.1'
s.add_dependency 'railties', '>= 3.1', '< 6.0' s.add_dependency 'railties', '>= 3.1', '< 7.1'
end end

View File

@ -0,0 +1,52 @@
require 'rswag/ui/configuration'
require_relative '../../spec_helper'
RSpec.describe Rswag::Ui::Configuration do
describe '#swagger_endpoints'
describe '#basic_auth_enabled' do
context 'when unspecified' do
it 'defaults to false' do
configuration = described_class.new
basic_auth_enabled = configuration.basic_auth_enabled
expect(basic_auth_enabled).to be(false)
end
end
context 'when specified' do
context 'when set to true' do
it 'returns true' do
configuration = described_class.new
configuration.basic_auth_enabled = true
basic_auth_enabled = configuration.basic_auth_enabled
expect(basic_auth_enabled).to be(true)
end
end
context 'when set to false' do
it 'returns false' do
configuration = described_class.new
configuration.basic_auth_enabled = false
basic_auth_enabled = configuration.basic_auth_enabled
expect(basic_auth_enabled).to be(false)
end
end
end
end
describe '#basic_auth_credentials' do
it 'sets the username and password' do
configuration = described_class.new
configuration.basic_auth_credentials 'foo', 'bar'
credentials = configuration.config_object[:basic_auth]
expect(credentials).to eq(username: 'foo', password: 'bar')
end
end
describe '#get_binding'
end

View File

@ -0,0 +1,100 @@
# This file was generated by the `rspec --init` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
# have no way to turn it off -- the option exists only for backwards
# compatibility in RSpec 3). It causes shared context metadata to be
# inherited by the metadata hash of host groups and examples, rather than
# triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
=begin
# This allows you to limit a spec run to individual examples or groups
# you care about by tagging them with `:focus` metadata. When nothing
# is tagged with `:focus`, all examples get run. RSpec also provides
# aliases for `it`, `describe`, and `context` that include `:focus`
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
config.filter_run_when_matching :focus
# Allows RSpec to persist some state between runs in order to support
# the `--only-failures` and `--next-failure` CLI options. We recommend
# you configure your source control system to ignore this file.
config.example_status_persistence_file_path = "spec/examples.txt"
# Limits the available syntax to the non-monkey patched syntax that is
# recommended. For more details, see:
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
config.disable_monkey_patching!
# This setting enables warnings. It's recommended, but in some cases may
# be too noisy due to issues in dependencies.
config.warnings = true
# Many RSpec users commonly either run the entire suite or an individual
# file, and it's useful to allow more verbose output when running an
# individual spec file.
if config.files_to_run.one?
# Use the documentation formatter for detailed output,
# unless a formatter has already been configured
# (e.g. via a command-line flag).
config.default_formatter = "doc"
end
# Print the 10 slowest examples and example groups at the
# end of the spec run, to help surface which specs are running
# particularly slow.
config.profile_examples = 10
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = :random
# Seed global randomization in this process using the `--seed` CLI option.
# Setting this allows you to use `--seed` to deterministically reproduce
# test failures related to randomization by passing the same `--seed` value
# as the one that triggered the failure.
Kernel.srand config.seed
=end
end

File diff suppressed because it is too large Load Diff

View File

@ -1,125 +0,0 @@
/* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block;
}
body {
line-height: 1;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,250 +0,0 @@
.swagger-section #header a#logo {
font-size: 1.5em;
font-weight: bold;
text-decoration: none;
background: transparent url(<%= asset_path('swagger-ui/images/logo.png') %>) no-repeat left center;
padding: 20px 0 20px 40px;
}
#text-head {
font-size: 80px;
font-family: 'Roboto', sans-serif;
color: #ffffff;
float: right;
margin-right: 20%;
}
.navbar-fixed-top .navbar-nav {
height: auto;
}
.navbar-fixed-top .navbar-brand {
height: auto;
}
.navbar-header {
height: auto;
}
.navbar-inverse {
background-color: #000;
border-color: #000;
}
#navbar-brand {
margin-left: 20%;
}
.navtext {
font-size: 10px;
}
.h1,
h1 {
font-size: 60px;
}
.navbar-default .navbar-header .navbar-brand {
color: #a2dfee;
}
/* tag titles */
.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a {
color: #393939;
font-family: 'Arvo', serif;
font-size: 1.5em;
}
.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover {
color: black;
}
.swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 {
color: #525252;
padding-left: 0px;
display: block;
clear: none;
float: left;
font-family: 'Arvo', serif;
font-weight: bold;
}
.navbar-default .navbar-collapse,
.navbar-default .navbar-form {
border-color: #0A0A0A;
}
.container1 {
width: 1500px;
margin: auto;
margin-top: 0;
background-image: url(<%= asset_path('swagger-ui/images/shield.png') %>);
background-repeat: no-repeat;
background-position: -40px -20px;
margin-bottom: 210px;
}
.container-inner {
width: 1200px;
margin: auto;
background-color: rgba(223, 227, 228, 0.75);
padding-bottom: 40px;
padding-top: 40px;
border-radius: 15px;
}
.header-content {
padding: 0;
width: 1000px;
}
.title1 {
font-size: 80px;
font-family: 'Vollkorn', serif;
color: #404040;
text-align: center;
padding-top: 40px;
padding-bottom: 100px;
}
#icon {
margin-top: -18px;
}
.subtext {
font-size: 25px;
font-style: italic;
color: #08b;
text-align: right;
padding-right: 250px;
}
.bg-primary {
background-color: #00468b;
}
.navbar-default .nav > li > a,
.navbar-default .nav > li > a:focus {
color: #08b;
}
.navbar-default .nav > li > a,
.navbar-default .nav > li > a:hover {
color: #08b;
}
.navbar-default .nav > li > a,
.navbar-default .nav > li > a:focus:hover {
color: #08b;
}
.text-faded {
font-size: 25px;
font-family: 'Vollkorn', serif;
}
.section-heading {
font-family: 'Vollkorn', serif;
font-size: 45px;
padding-bottom: 10px;
}
hr {
border-color: #00468b;
padding-bottom: 10px;
}
.description {
margin-top: 20px;
padding-bottom: 200px;
}
.description li {
font-family: 'Vollkorn', serif;
font-size: 25px;
color: #525252;
margin-left: 28%;
padding-top: 5px;
}
.gap {
margin-top: 200px;
}
.troubleshootingtext {
color: rgba(255, 255, 255, 0.7);
padding-left: 30%;
}
.troubleshootingtext li {
list-style-type: circle;
font-size: 25px;
padding-bottom: 5px;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.block.response_body.json:hover {
cursor: pointer;
}
.backdrop {
color: blue;
}
#myModal {
height: 100%;
}
.modal-backdrop {
bottom: 0;
position: fixed;
}
.curl {
padding: 10px;
font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace;
font-size: 0.9em;
max-height: 400px;
margin-top: 5px;
overflow-y: auto;
background-color: #fcf6db;
border: 1px solid #e5e0c6;
border-radius: 4px;
}
.curl_title {
font-size: 1.1em;
margin: 0;
padding: 15px 0 5px;
font-family: 'Open Sans', 'Helvetica Neue', Arial, sans-serif;
font-weight: 500;
line-height: 1.1;
}
.footer {
display: none;
}
.swagger-section .swagger-ui-wrap h2 {
padding: 0;
}
h2 {
margin: 0;
margin-bottom: 5px;
}
.markdown p {
font-size: 15px;
font-family: 'Arvo', serif;
}
.swagger-section .swagger-ui-wrap .code {
font-size: 15px;
font-family: 'Arvo', serif;
}
.swagger-section .swagger-ui-wrap b {
font-family: 'Arvo', serif;
}
#signin:hover {
cursor: pointer;
}
.dropdown-menu {
padding: 15px;
}
.navbar-right .dropdown-menu {
left: 0;
right: auto;
}
#signinbutton {
width: 100%;
height: 32px;
font-size: 13px;
font-weight: bold;
color: #08b;
}
.navbar-default .nav > li .details {
color: #000000;
text-transform: none;
font-size: 15px;
font-weight: normal;
font-family: 'Open Sans', sans-serif;
font-style: italic;
line-height: 20px;
top: -2px;
}
.navbar-default .nav > li .details:hover {
color: black;
}
#signout {
width: 100%;
height: 32px;
font-size: 13px;
font-weight: bold;
color: #08b;
}

View File

@ -1,14 +0,0 @@
/* Google Font's Droid Sans */
@font-face {
font-family: 'Droid Sans';
font-style: normal;
font-weight: 400;
src: local('Droid Sans'), local('DroidSans'), url(<%= asset_path('swagger-ui/fonts/DroidSans.ttf') %>), format('truetype');
}
/* Google Font's Droid Sans Bold */
@font-face {
font-family: 'Droid Sans';
font-style: normal;
font-weight: 700;
src: local('Droid Sans Bold'), local('DroidSans-Bold'), url(<%= asset_path('swagger-ui/fonts/DroidSans-Bold.ttf') %>), format('truetype');
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 445 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Advertència: Obsolet",
"Implementation Notes":"Notes d'implementació",
"Response Class":"Classe de la Resposta",
"Status":"Estatus",
"Parameters":"Paràmetres",
"Parameter":"Paràmetre",
"Value":"Valor",
"Description":"Descripció",
"Parameter Type":"Tipus del Paràmetre",
"Data Type":"Tipus de la Dada",
"Response Messages":"Missatges de la Resposta",
"HTTP Status Code":"Codi d'Estatus HTTP",
"Reason":"Raó",
"Response Model":"Model de la Resposta",
"Request URL":"URL de la Sol·licitud",
"Response Body":"Cos de la Resposta",
"Response Code":"Codi de la Resposta",
"Response Headers":"Capçaleres de la Resposta",
"Hide Response":"Amagar Resposta",
"Try it out!":"Prova-ho!",
"Show/Hide":"Mostrar/Amagar",
"List Operations":"Llista Operacions",
"Expand Operations":"Expandir Operacions",
"Raw":"Cru",
"can't parse JSON. Raw result":"no puc analitzar el JSON. Resultat cru",
"Example Value":"Valor d'Exemple",
"Model Schema":"Esquema del Model",
"Model":"Model",
"apply":"aplicar",
"Username":"Nom d'usuari",
"Password":"Contrasenya",
"Terms of service":"Termes del servei",
"Created by":"Creat per",
"See more at":"Veure més en",
"Contact the developer":"Contactar amb el desenvolupador",
"api version":"versió de la api",
"Response Content Type":"Tipus de Contingut de la Resposta",
"fetching resource":"recollint recurs",
"fetching resource list":"recollins llista de recursos",
"Explore":"Explorant",
"Show Swagger Petstore Example Apis":"Mostrar API d'Exemple Swagger Petstore",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"No es pot llegir del servidor. Potser no teniu la configuració de control d'accés apropiada.",
"Please specify the protocol for":"Si us plau, especifiqueu el protocol per a",
"Can't read swagger JSON from":"No es pot llegir el JSON de swagger des de",
"Finished Loading Resource Information. Rendering Swagger UI":"Finalitzada la càrrega del recurs informatiu. Renderitzant Swagger UI",
"Unable to read api":"No es pot llegir l'api",
"from path":"des de la ruta",
"server returned":"el servidor ha retornat"
});

View File

@ -1,56 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Warning: Deprecated",
"Implementation Notes":"Implementation Notes",
"Response Class":"Response Class",
"Status":"Status",
"Parameters":"Parameters",
"Parameter":"Parameter",
"Value":"Value",
"Description":"Description",
"Parameter Type":"Parameter Type",
"Data Type":"Data Type",
"Response Messages":"Response Messages",
"HTTP Status Code":"HTTP Status Code",
"Reason":"Reason",
"Response Model":"Response Model",
"Request URL":"Request URL",
"Response Body":"Response Body",
"Response Code":"Response Code",
"Response Headers":"Response Headers",
"Hide Response":"Hide Response",
"Headers":"Headers",
"Try it out!":"Try it out!",
"Show/Hide":"Show/Hide",
"List Operations":"List Operations",
"Expand Operations":"Expand Operations",
"Raw":"Raw",
"can't parse JSON. Raw result":"can't parse JSON. Raw result",
"Example Value":"Example Value",
"Model Schema":"Model Schema",
"Model":"Model",
"Click to set as parameter value":"Click to set as parameter value",
"apply":"apply",
"Username":"Username",
"Password":"Password",
"Terms of service":"Terms of service",
"Created by":"Created by",
"See more at":"See more at",
"Contact the developer":"Contact the developer",
"api version":"api version",
"Response Content Type":"Response Content Type",
"Parameter content type:":"Parameter content type:",
"fetching resource":"fetching resource",
"fetching resource list":"fetching resource list",
"Explore":"Explore",
"Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.",
"Please specify the protocol for":"Please specify the protocol for",
"Can't read swagger JSON from":"Can't read swagger JSON from",
"Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI",
"Unable to read api":"Unable to read api",
"from path":"from path",
"server returned":"server returned"
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Advertencia: Obsoleto",
"Implementation Notes":"Notas de implementación",
"Response Class":"Clase de la Respuesta",
"Status":"Status",
"Parameters":"Parámetros",
"Parameter":"Parámetro",
"Value":"Valor",
"Description":"Descripción",
"Parameter Type":"Tipo del Parámetro",
"Data Type":"Tipo del Dato",
"Response Messages":"Mensajes de la Respuesta",
"HTTP Status Code":"Código de Status HTTP",
"Reason":"Razón",
"Response Model":"Modelo de la Respuesta",
"Request URL":"URL de la Solicitud",
"Response Body":"Cuerpo de la Respuesta",
"Response Code":"Código de la Respuesta",
"Response Headers":"Encabezados de la Respuesta",
"Hide Response":"Ocultar Respuesta",
"Try it out!":"Pruébalo!",
"Show/Hide":"Mostrar/Ocultar",
"List Operations":"Listar Operaciones",
"Expand Operations":"Expandir Operaciones",
"Raw":"Crudo",
"can't parse JSON. Raw result":"no puede parsear el JSON. Resultado crudo",
"Example Value":"Valor de Ejemplo",
"Model Schema":"Esquema del Modelo",
"Model":"Modelo",
"apply":"aplicar",
"Username":"Nombre de usuario",
"Password":"Contraseña",
"Terms of service":"Términos de Servicio",
"Created by":"Creado por",
"See more at":"Ver más en",
"Contact the developer":"Contactar al desarrollador",
"api version":"versión de la api",
"Response Content Type":"Tipo de Contenido (Content Type) de la Respuesta",
"fetching resource":"buscando recurso",
"fetching resource list":"buscando lista del recurso",
"Explore":"Explorar",
"Show Swagger Petstore Example Apis":"Mostrar Api Ejemplo de Swagger Petstore",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"No se puede leer del servidor. Tal vez no tiene la configuración de control de acceso de origen (access-control-origin) apropiado.",
"Please specify the protocol for":"Por favor, especificar el protocola para",
"Can't read swagger JSON from":"No se puede leer el JSON de swagger desde",
"Finished Loading Resource Information. Rendering Swagger UI":"Finalizada la carga del recurso de Información. Mostrando Swagger UI",
"Unable to read api":"No se puede leer la api",
"from path":"desde ruta",
"server returned":"el servidor retornó"
});

View File

@ -1,54 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Avertissement : Obsolète",
"Implementation Notes":"Notes d'implémentation",
"Response Class":"Classe de la réponse",
"Status":"Statut",
"Parameters":"Paramètres",
"Parameter":"Paramètre",
"Value":"Valeur",
"Description":"Description",
"Parameter Type":"Type du paramètre",
"Data Type":"Type de données",
"Response Messages":"Messages de la réponse",
"HTTP Status Code":"Code de statut HTTP",
"Reason":"Raison",
"Response Model":"Modèle de réponse",
"Request URL":"URL appelée",
"Response Body":"Corps de la réponse",
"Response Code":"Code de la réponse",
"Response Headers":"En-têtes de la réponse",
"Hide Response":"Cacher la réponse",
"Headers":"En-têtes",
"Try it out!":"Testez !",
"Show/Hide":"Afficher/Masquer",
"List Operations":"Liste des opérations",
"Expand Operations":"Développer les opérations",
"Raw":"Brut",
"can't parse JSON. Raw result":"impossible de décoder le JSON. Résultat brut",
"Example Value":"Exemple la valeur",
"Model Schema":"Définition du modèle",
"Model":"Modèle",
"apply":"appliquer",
"Username":"Nom d'utilisateur",
"Password":"Mot de passe",
"Terms of service":"Conditions de service",
"Created by":"Créé par",
"See more at":"Voir plus sur",
"Contact the developer":"Contacter le développeur",
"api version":"version de l'api",
"Response Content Type":"Content Type de la réponse",
"fetching resource":"récupération de la ressource",
"fetching resource list":"récupération de la liste de ressources",
"Explore":"Explorer",
"Show Swagger Petstore Example Apis":"Montrer les Apis de l'exemple Petstore de Swagger",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Impossible de lire à partir du serveur. Il se peut que les réglages access-control-origin ne soient pas appropriés.",
"Please specify the protocol for":"Veuillez spécifier un protocole pour",
"Can't read swagger JSON from":"Impossible de lire le JSON swagger à partir de",
"Finished Loading Resource Information. Rendering Swagger UI":"Chargement des informations terminé. Affichage de Swagger UI",
"Unable to read api":"Impossible de lire l'api",
"from path":"à partir du chemin",
"server returned":"réponse du serveur"
});

View File

@ -1,56 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"ყურადღება: აღარ გამოიყენება",
"Implementation Notes":"იმპლემენტაციის აღწერა",
"Response Class":"რესპონს კლასი",
"Status":"სტატუსი",
"Parameters":"პარამეტრები",
"Parameter":"პარამეტრი",
"Value":"მნიშვნელობა",
"Description":"აღწერა",
"Parameter Type":"პარამეტრის ტიპი",
"Data Type":"მონაცემის ტიპი",
"Response Messages":"პასუხი",
"HTTP Status Code":"HTTP სტატუსი",
"Reason":"მიზეზი",
"Response Model":"რესპონს მოდელი",
"Request URL":"მოთხოვნის URL",
"Response Body":"პასუხის სხეული",
"Response Code":"პასუხის კოდი",
"Response Headers":"პასუხის ჰედერები",
"Hide Response":"დამალე პასუხი",
"Headers":"ჰედერები",
"Try it out!":"ცადე !",
"Show/Hide":"გამოჩენა/დამალვა",
"List Operations":"ოპერაციების სია",
"Expand Operations":"ოპერაციები ვრცლად",
"Raw":"ნედლი",
"can't parse JSON. Raw result":"JSON-ის დამუშავება ვერ მოხერხდა. ნედლი პასუხი",
"Example Value":"მაგალითი",
"Model Schema":"მოდელის სტრუქტურა",
"Model":"მოდელი",
"Click to set as parameter value":"პარამეტრისთვის მნიშვნელობის მისანიჭებლად, დააკლიკე",
"apply":"გამოყენება",
"Username":"მოხმარებელი",
"Password":"პაროლი",
"Terms of service":"მომსახურების პირობები",
"Created by":"შექმნა",
"See more at":"ნახე ვრცლად",
"Contact the developer":"დაუკავშირდი დეველოპერს",
"api version":"api ვერსია",
"Response Content Type":"პასუხის კონტენტის ტიპი",
"Parameter content type:":"პარამეტრის კონტენტის ტიპი:",
"fetching resource":"რესურსების მიღება",
"fetching resource list":"რესურსების სიის მიღება",
"Explore":"ნახვა",
"Show Swagger Petstore Example Apis":"ნახე Swagger Petstore სამაგალითო Api",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"სერვერთან დაკავშირება ვერ ხერხდება. შეამოწმეთ access-control-origin.",
"Please specify the protocol for":"მიუთითეთ პროტოკოლი",
"Can't read swagger JSON from":"swagger JSON წაკითხვა ვერ მოხერხდა",
"Finished Loading Resource Information. Rendering Swagger UI":"რესურსების ჩატვირთვა სრულდება. Swagger UI რენდერდება",
"Unable to read api":"api წაკითხვა ვერ მოხერხდა",
"from path":"მისამართიდან",
"server returned":"სერვერმა დააბრუნა"
});

View File

@ -1,52 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Attenzione: Deprecato",
"Implementation Notes":"Note di implementazione",
"Response Class":"Classe della risposta",
"Status":"Stato",
"Parameters":"Parametri",
"Parameter":"Parametro",
"Value":"Valore",
"Description":"Descrizione",
"Parameter Type":"Tipo di parametro",
"Data Type":"Tipo di dato",
"Response Messages":"Messaggi della risposta",
"HTTP Status Code":"Codice stato HTTP",
"Reason":"Motivo",
"Response Model":"Modello di risposta",
"Request URL":"URL della richiesta",
"Response Body":"Corpo della risposta",
"Response Code":"Oggetto della risposta",
"Response Headers":"Intestazioni della risposta",
"Hide Response":"Nascondi risposta",
"Try it out!":"Provalo!",
"Show/Hide":"Mostra/Nascondi",
"List Operations":"Mostra operazioni",
"Expand Operations":"Espandi operazioni",
"Raw":"Grezzo (raw)",
"can't parse JSON. Raw result":"non è possibile parsare il JSON. Risultato grezzo (raw).",
"Model Schema":"Schema del modello",
"Model":"Modello",
"apply":"applica",
"Username":"Nome utente",
"Password":"Password",
"Terms of service":"Condizioni del servizio",
"Created by":"Creato da",
"See more at":"Informazioni aggiuntive:",
"Contact the developer":"Contatta lo sviluppatore",
"api version":"versione api",
"Response Content Type":"Tipo di contenuto (content type) della risposta",
"fetching resource":"recuperando la risorsa",
"fetching resource list":"recuperando lista risorse",
"Explore":"Esplora",
"Show Swagger Petstore Example Apis":"Mostra le api di esempio di Swagger Petstore",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Non è possibile leggere dal server. Potrebbe non avere le impostazioni di controllo accesso origine (access-control-origin) appropriate.",
"Please specify the protocol for":"Si prega di specificare il protocollo per",
"Can't read swagger JSON from":"Impossibile leggere JSON swagger da:",
"Finished Loading Resource Information. Rendering Swagger UI":"Lettura informazioni risorse termianta. Swagger UI viene mostrata",
"Unable to read api":"Impossibile leggere la api",
"from path":"da cartella",
"server returned":"il server ha restituito"
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"警告: 廃止予定",
"Implementation Notes":"実装メモ",
"Response Class":"レスポンスクラス",
"Status":"ステータス",
"Parameters":"パラメータ群",
"Parameter":"パラメータ",
"Value":"値",
"Description":"説明",
"Parameter Type":"パラメータタイプ",
"Data Type":"データタイプ",
"Response Messages":"レスポンスメッセージ",
"HTTP Status Code":"HTTPステータスコード",
"Reason":"理由",
"Response Model":"レスポンスモデル",
"Request URL":"リクエストURL",
"Response Body":"レスポンスボディ",
"Response Code":"レスポンスコード",
"Response Headers":"レスポンスヘッダ",
"Hide Response":"レスポンスを隠す",
"Headers":"ヘッダ",
"Try it out!":"実際に実行!",
"Show/Hide":"表示/非表示",
"List Operations":"操作一覧",
"Expand Operations":"操作の展開",
"Raw":"Raw",
"can't parse JSON. Raw result":"JSONへ解釈できません. 未加工の結果",
"Model Schema":"モデルスキーマ",
"Model":"モデル",
"apply":"実行",
"Username":"ユーザ名",
"Password":"パスワード",
"Terms of service":"サービス利用規約",
"Created by":"Created by",
"See more at":"See more at",
"Contact the developer":"開発者に連絡",
"api version":"APIバージョン",
"Response Content Type":"レスポンス コンテンツタイプ",
"fetching resource":"リソースの取得",
"fetching resource list":"リソース一覧の取得",
"Explore":"Explore",
"Show Swagger Petstore Example Apis":"SwaggerペットストアAPIの表示",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"サーバから読み込めません. 適切なaccess-control-origin設定を持っていない可能性があります.",
"Please specify the protocol for":"プロトコルを指定してください",
"Can't read swagger JSON from":"次からswagger JSONを読み込めません",
"Finished Loading Resource Information. Rendering Swagger UI":"リソース情報の読み込みが完了しました. Swagger UIを描画しています",
"Unable to read api":"APIを読み込めません",
"from path":"次のパスから",
"server returned":"サーバからの返答"
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"경고:폐기예정됨",
"Implementation Notes":"구현 노트",
"Response Class":"응답 클래스",
"Status":"상태",
"Parameters":"매개변수들",
"Parameter":"매개변수",
"Value":"값",
"Description":"설명",
"Parameter Type":"매개변수 타입",
"Data Type":"데이터 타입",
"Response Messages":"응답 메세지",
"HTTP Status Code":"HTTP 상태 코드",
"Reason":"원인",
"Response Model":"응답 모델",
"Request URL":"요청 URL",
"Response Body":"응답 본문",
"Response Code":"응답 코드",
"Response Headers":"응답 헤더",
"Hide Response":"응답 숨기기",
"Headers":"헤더",
"Try it out!":"써보기!",
"Show/Hide":"보이기/숨기기",
"List Operations":"목록 작업",
"Expand Operations":"전개 작업",
"Raw":"원본",
"can't parse JSON. Raw result":"JSON을 파싱할수 없음. 원본결과:",
"Model Schema":"모델 스키마",
"Model":"모델",
"apply":"적용",
"Username":"사용자 이름",
"Password":"암호",
"Terms of service":"이용약관",
"Created by":"작성자",
"See more at":"추가정보:",
"Contact the developer":"개발자에게 문의",
"api version":"api버전",
"Response Content Type":"응답Content Type",
"fetching resource":"리소스 가져오기",
"fetching resource list":"리소스 목록 가져오기",
"Explore":"탐색",
"Show Swagger Petstore Example Apis":"Swagger Petstore 예제 보기",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"서버로부터 읽어들일수 없습니다. access-control-origin 설정이 올바르지 않을수 있습니다.",
"Please specify the protocol for":"다음을 위한 프로토콜을 정하세요",
"Can't read swagger JSON from":"swagger JSON 을 다음으로 부터 읽을수 없습니다",
"Finished Loading Resource Information. Rendering Swagger UI":"리소스 정보 불러오기 완료. Swagger UI 랜더링",
"Unable to read api":"api를 읽을 수 없습니다.",
"from path":"다음 경로로 부터",
"server returned":"서버 응답함."
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Uwaga: Wycofane",
"Implementation Notes":"Uwagi Implementacji",
"Response Class":"Klasa Odpowiedzi",
"Status":"Status",
"Parameters":"Parametry",
"Parameter":"Parametr",
"Value":"Wartość",
"Description":"Opis",
"Parameter Type":"Typ Parametru",
"Data Type":"Typ Danych",
"Response Messages":"Wiadomości Odpowiedzi",
"HTTP Status Code":"Kod Statusu HTTP",
"Reason":"Przyczyna",
"Response Model":"Model Odpowiedzi",
"Request URL":"URL Wywołania",
"Response Body":"Treść Odpowiedzi",
"Response Code":"Kod Odpowiedzi",
"Response Headers":"Nagłówki Odpowiedzi",
"Hide Response":"Ukryj Odpowiedź",
"Headers":"Nagłówki",
"Try it out!":"Wypróbuj!",
"Show/Hide":"Pokaż/Ukryj",
"List Operations":"Lista Operacji",
"Expand Operations":"Rozwiń Operacje",
"Raw":"Nieprzetworzone",
"can't parse JSON. Raw result":"nie można przetworzyć pliku JSON. Nieprzetworzone dane",
"Model Schema":"Schemat Modelu",
"Model":"Model",
"apply":"użyj",
"Username":"Nazwa użytkownika",
"Password":"Hasło",
"Terms of service":"Warunki używania",
"Created by":"Utworzone przez",
"See more at":"Zobacz więcej na",
"Contact the developer":"Kontakt z deweloperem",
"api version":"wersja api",
"Response Content Type":"Typ Zasobu Odpowiedzi",
"fetching resource":"ładowanie zasobu",
"fetching resource list":"ładowanie listy zasobów",
"Explore":"Eksploruj",
"Show Swagger Petstore Example Apis":"Pokaż Przykładowe Api Swagger Petstore",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Brak połączenia z serwerem. Może on nie mieć odpowiednich ustawień access-control-origin.",
"Please specify the protocol for":"Proszę podać protokół dla",
"Can't read swagger JSON from":"Nie można odczytać swagger JSON z",
"Finished Loading Resource Information. Rendering Swagger UI":"Ukończono Ładowanie Informacji o Zasobie. Renderowanie Swagger UI",
"Unable to read api":"Nie można odczytać api",
"from path":"ze ścieżki",
"server returned":"serwer zwrócił"
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Aviso: Depreciado",
"Implementation Notes":"Notas de Implementação",
"Response Class":"Classe de resposta",
"Status":"Status",
"Parameters":"Parâmetros",
"Parameter":"Parâmetro",
"Value":"Valor",
"Description":"Descrição",
"Parameter Type":"Tipo de parâmetro",
"Data Type":"Tipo de dados",
"Response Messages":"Mensagens de resposta",
"HTTP Status Code":"Código de status HTTP",
"Reason":"Razão",
"Response Model":"Modelo resposta",
"Request URL":"URL requisição",
"Response Body":"Corpo da resposta",
"Response Code":"Código da resposta",
"Response Headers":"Cabeçalho da resposta",
"Headers":"Cabeçalhos",
"Hide Response":"Esconder resposta",
"Try it out!":"Tente agora!",
"Show/Hide":"Mostrar/Esconder",
"List Operations":"Listar operações",
"Expand Operations":"Expandir operações",
"Raw":"Cru",
"can't parse JSON. Raw result":"Falha ao analisar JSON. Resulto cru",
"Model Schema":"Modelo esquema",
"Model":"Modelo",
"apply":"Aplicar",
"Username":"Usuário",
"Password":"Senha",
"Terms of service":"Termos do serviço",
"Created by":"Criado por",
"See more at":"Veja mais em",
"Contact the developer":"Contate o desenvolvedor",
"api version":"Versão api",
"Response Content Type":"Tipo de conteúdo da resposta",
"fetching resource":"busca recurso",
"fetching resource list":"buscando lista de recursos",
"Explore":"Explorar",
"Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Não é possível ler do servidor. Pode não ter as apropriadas configurações access-control-origin",
"Please specify the protocol for":"Por favor especifique o protocolo",
"Can't read swagger JSON from":"Não é possível ler o JSON Swagger de",
"Finished Loading Resource Information. Rendering Swagger UI":"Carregar informação de recurso finalizada. Renderizando Swagger UI",
"Unable to read api":"Não foi possível ler api",
"from path":"do caminho",
"server returned":"servidor retornou"
});

View File

@ -1,56 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Предупреждение: Устарело",
"Implementation Notes":"Заметки",
"Response Class":"Пример ответа",
"Status":"Статус",
"Parameters":"Параметры",
"Parameter":"Параметр",
"Value":"Значение",
"Description":"Описание",
"Parameter Type":"Тип параметра",
"Data Type":"Тип данных",
"HTTP Status Code":"HTTP код",
"Reason":"Причина",
"Response Model":"Структура ответа",
"Request URL":"URL запроса",
"Response Body":"Тело ответа",
"Response Code":"HTTP код ответа",
"Response Headers":"Заголовки ответа",
"Hide Response":"Спрятать ответ",
"Headers":"Заголовки",
"Response Messages":"Что может прийти в ответ",
"Try it out!":"Попробовать!",
"Show/Hide":"Показать/Скрыть",
"List Operations":"Операции кратко",
"Expand Operations":"Операции подробно",
"Raw":"В сыром виде",
"can't parse JSON. Raw result":"Не удается распарсить ответ:",
"Example Value":"Пример",
"Model Schema":"Структура",
"Model":"Описание",
"Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра",
"apply":"применить",
"Username":"Имя пользователя",
"Password":"Пароль",
"Terms of service":"Условия использования",
"Created by":"Разработано",
"See more at":"Еще тут",
"Contact the developer":"Связаться с разработчиком",
"api version":"Версия API",
"Response Content Type":"Content Type ответа",
"Parameter content type:":"Content Type параметра:",
"fetching resource":"Получение ресурса",
"fetching resource list":"Получение ресурсов",
"Explore":"Показать",
"Show Swagger Petstore Example Apis":"Показать примеры АПИ",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа",
"Please specify the protocol for":"Пожалуйста, укажите протокол для",
"Can't read swagger JSON from":"Не получается прочитать swagger json из",
"Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим",
"Unable to read api":"Не удалось прочитать api",
"from path":"по адресу",
"server returned":"сервер сказал"
});

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Uyarı: Deprecated",
"Implementation Notes":"Gerçekleştirim Notları",
"Response Class":"Dönen Sınıf",
"Status":"Statü",
"Parameters":"Parametreler",
"Parameter":"Parametre",
"Value":"Değer",
"Description":"Açıklama",
"Parameter Type":"Parametre Tipi",
"Data Type":"Veri Tipi",
"Response Messages":"Dönüş Mesajı",
"HTTP Status Code":"HTTP Statü Kodu",
"Reason":"Gerekçe",
"Response Model":"Dönüş Modeli",
"Request URL":"İstek URL",
"Response Body":"Dönüş İçeriği",
"Response Code":"Dönüş Kodu",
"Response Headers":"Dönüş Üst Bilgileri",
"Hide Response":"Dönüşü Gizle",
"Headers":"Üst Bilgiler",
"Try it out!":"Dene!",
"Show/Hide":"Göster/Gizle",
"List Operations":"Operasyonları Listele",
"Expand Operations":"Operasyonları Aç",
"Raw":"Ham",
"can't parse JSON. Raw result":"JSON çözümlenemiyor. Ham sonuç",
"Model Schema":"Model Şema",
"Model":"Model",
"apply":"uygula",
"Username":"Kullanıcı Adı",
"Password":"Parola",
"Terms of service":"Servis şartları",
"Created by":"Oluşturan",
"See more at":"Daha fazlası için",
"Contact the developer":"Geliştirici ile İletişime Geçin",
"api version":"api versiyon",
"Response Content Type":"Dönüş İçerik Tipi",
"fetching resource":"kaynak getiriliyor",
"fetching resource list":"kaynak listesi getiriliyor",
"Explore":"Keşfet",
"Show Swagger Petstore Example Apis":"Swagger Petstore Örnek Api'yi Gör",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Sunucudan okuma yapılamıyor. Sunucu access-control-origin ayarlarınızı kontrol edin.",
"Please specify the protocol for":"Lütfen istenen adres için protokol belirtiniz",
"Can't read swagger JSON from":"Swagger JSON bu kaynaktan okunamıyor",
"Finished Loading Resource Information. Rendering Swagger UI":"Kaynak baglantısı tamamlandı. Swagger UI gösterime hazırlanıyor",
"Unable to read api":"api okunamadı",
"from path":"yoldan",
"server returned":"sunucuya dönüldü"
});

View File

@ -1,39 +0,0 @@
'use strict';
/**
* Translator for documentation pages.
*
* To enable translation you should include one of language-files in your index.html
* after <script src='lang/translator.js' type='text/javascript'></script>.
* For example - <script src='lang/ru.js' type='text/javascript'></script>
*
* If you wish to translate some new texts you should do two things:
* 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too.
* 2. Mark that text it templates this way <anyHtmlTag data-sw-translate>New Phrase</anyHtmlTag> or <anyHtmlTag data-sw-translate value='New Phrase'/>.
* The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate.
*
*/
window.SwaggerTranslator = {
_words:[],
translate: function(sel) {
var $this = this;
sel = sel || '[data-sw-translate]';
$(sel).each(function() {
$(this).html($this._tryTranslate($(this).html()));
$(this).val($this._tryTranslate($(this).val()));
$(this).attr('title', $this._tryTranslate($(this).attr('title')));
});
},
_tryTranslate: function(word) {
return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word;
},
learn: function(wordsMap) {
this._words = wordsMap;
}
};

View File

@ -1,53 +0,0 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"警告:已过时",
"Implementation Notes":"实现备注",
"Response Class":"响应类",
"Status":"状态",
"Parameters":"参数",
"Parameter":"参数",
"Value":"值",
"Description":"描述",
"Parameter Type":"参数类型",
"Data Type":"数据类型",
"Response Messages":"响应消息",
"HTTP Status Code":"HTTP状态码",
"Reason":"原因",
"Response Model":"响应模型",
"Request URL":"请求URL",
"Response Body":"响应体",
"Response Code":"响应码",
"Response Headers":"响应头",
"Hide Response":"隐藏响应",
"Headers":"头",
"Try it out!":"试一下!",
"Show/Hide":"显示/隐藏",
"List Operations":"显示操作",
"Expand Operations":"展开操作",
"Raw":"原始",
"can't parse JSON. Raw result":"无法解析JSON. 原始结果",
"Model Schema":"模型架构",
"Model":"模型",
"apply":"应用",
"Username":"用户名",
"Password":"密码",
"Terms of service":"服务条款",
"Created by":"创建者",
"See more at":"查看更多:",
"Contact the developer":"联系开发者",
"api version":"api版本",
"Response Content Type":"响应Content Type",
"fetching resource":"正在获取资源",
"fetching resource list":"正在获取资源列表",
"Explore":"浏览",
"Show Swagger Petstore Example Apis":"显示 Swagger Petstore 示例 Apis",
"Can't read from server. It may not have the appropriate access-control-origin settings.":"无法从服务器读取。可能没有正确设置access-control-origin。",
"Please specify the protocol for":"请指定协议:",
"Can't read swagger JSON from":"无法读取swagger JSON于",
"Finished Loading Resource Information. Rendering Swagger UI":"已加载资源信息。正在渲染Swagger UI",
"Unable to read api":"无法读取api",
"from path":"从路径",
"server returned":"服务器返回"
});

Some files were not shown because too many files have changed in this diff Show More