grape-swagger 0.23.0 → 0.24.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +1 -1
- data/CHANGELOG.md +20 -2
- data/Dangerfile +1 -1
- data/Gemfile +5 -1
- data/README.md +172 -5
- data/lib/grape-swagger.rb +9 -1
- data/lib/grape-swagger/doc_methods.rb +22 -29
- data/lib/grape-swagger/doc_methods/parse_params.rb +2 -0
- data/lib/grape-swagger/endpoint.rb +29 -10
- data/lib/grape-swagger/rake/oapi_tasks.rb +99 -0
- data/lib/grape-swagger/version.rb +1 -1
- data/spec/issues/430_entity_definitions_spec.rb +48 -0
- data/spec/lib/oapi_tasks_spec.rb +133 -0
- data/spec/swagger_v2/api_swagger_v2_body_definitions_spec.rb +2 -0
- data/spec/swagger_v2/description_not_initialized.rb +0 -2
- data/spec/swagger_v2/guarded_endpoint_spec.rb +116 -0
- data/spec/swagger_v2/host.rb +0 -2
- data/spec/swagger_v2/namespaced_api_spec.rb +52 -0
- data/spec/swagger_v2/params_array_collection_fromat_spec.rb +80 -0
- data/spec/swagger_v2/security_requirement_spec.rb +23 -0
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99ac4d378547c6998e6c712a83eb82d8277786fb
|
4
|
+
data.tar.gz: 9d18548301ad46bd474671a770c5e528ee7a4f3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b609366f8b1e964dbffbc0a65593bca55d050ac46cac23896627fd0b2b49f9a2b4fc368022e20d3e2866d458322d083a13f1bc44d7cc36c4bff323d7082497ed
|
7
|
+
data.tar.gz: 6c6e93549bf4b7eebc659155dcb21ce5d999ef811ea1f8dbceb7c6104b35c3765d0ea6ef16fb706303f9dcd86c99811862fd939af471cbb1a5ff730c9c07aa50
|
data/.rubocop_todo.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -8,12 +8,30 @@
|
|
8
8
|
|
9
9
|
* Your contribution here.
|
10
10
|
|
11
|
+
### 0.24.0 (September 23, 2016)
|
12
|
+
|
13
|
+
#### Features
|
14
|
+
|
15
|
+
* [#504](https://github.com/ruby-grape/grape-swagger/pull/504): Added support for set the 'collectionFormat' of arrays - [@rczjns](https://github.com/rczjns).
|
16
|
+
* [#502](https://github.com/ruby-grape/grape-swagger/pull/502): Adds specs for rake tasks - [@LeFnord](https://github.com/LeFnord).
|
17
|
+
* [#501](https://github.com/ruby-grape/grape-swagger/pull/501): Adds getting of a specified resource for Rake Tasks - [@LeFnord](https://github.com/LeFnord).
|
18
|
+
* [#500](https://github.com/ruby-grape/grape-swagger/pull/500): Adds Rake tasks to get and validate OAPI/Swagger documentation - [@LeFnord](https://github.com/LeFnord).
|
19
|
+
* [#493](https://github.com/ruby-grape/grape-swagger/pull/493): Swagger UI endpoint authorization. - [@texpert](https://github.com/texpert).
|
20
|
+
* [#492](https://github.com/ruby-grape/grape/pull/492): Define security requirements on endpoint methods - [@tomregelink](https://github.com/tomregelink).
|
21
|
+
* [#497](https://github.com/ruby-grape/grape-swagger/pull/497): Use ruby-grape-danger in Dangerfile - [@dblock](https://github.com/dblock).
|
22
|
+
|
23
|
+
#### Fixes
|
24
|
+
|
25
|
+
* [#503](https://github.com/ruby-grape/grape-swagger/pull/503): Corrects exposing of inline definitions - [@LeFnord](https://github.com/LeFnord).
|
26
|
+
* [#494](https://github.com/ruby-grape/grape-swagger/pull/494): Header parametes are now included in documentation when body parameters have been defined - [@anakinj](https://github.com/anakinj).
|
27
|
+
* [#505](https://github.com/ruby-grape/grape-swagger/pull/505): Combines namespaces with their mounted paths to allow APIs with specified mount_paths - [@KevinLiddle](https://github.com/KevinLiddle).
|
28
|
+
|
11
29
|
### 0.23.0 (August 5, 2016)
|
12
30
|
|
13
31
|
#### Features
|
14
32
|
|
15
|
-
* [#491](https://github.com/ruby-grape/grape/pull/491): Add `ignore_defaults` option - [@pezholio](https://github.com/pezholio).
|
16
|
-
* [#486](https://github.com/ruby-grape/grape/pull/486): Use an automated PR linter, [danger.systems](http://danger.systems) - [@dblock](https://github.com/dblock).
|
33
|
+
* [#491](https://github.com/ruby-grape/grape-swagger/pull/491): Add `ignore_defaults` option - [@pezholio](https://github.com/pezholio).
|
34
|
+
* [#486](https://github.com/ruby-grape/grape-swagger/pull/486): Use an automated PR linter, [danger.systems](http://danger.systems) - [@dblock](https://github.com/dblock).
|
17
35
|
|
18
36
|
#### Fixes
|
19
37
|
|
data/Dangerfile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
danger.import_dangerfile(gem: 'ruby-grape-danger')
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -14,10 +14,12 @@
|
|
14
14
|
* [Model Parsers](#model_parsers)
|
15
15
|
* [Configure](#configure)
|
16
16
|
* [Routes Configuration](#routes)
|
17
|
+
* [Securing the Swagger UI](#oauth)
|
17
18
|
* [Markdown](#md_usage)
|
18
19
|
* [Response documentation](#response)
|
19
20
|
* [Extensions](#extensions)
|
20
21
|
* [Example](#example)
|
22
|
+
* [Rake Tasks](#rake)
|
21
23
|
|
22
24
|
<a name="what" />
|
23
25
|
## What is grape-swagger?
|
@@ -50,7 +52,7 @@ grape-swagger | swagger spec | grape | grape-entity | represen
|
|
50
52
|
0.20.1 | 2.0 | >= 0.12.0 ... <= 0.14.0 | <= 0.5.1 | n/a |
|
51
53
|
0.20.3 | 2.0 | >= 0.12.0 ... ~> 0.16.2 | ~> 0.5.1 | n/a |
|
52
54
|
0.21.0 | 2.0 | >= 0.12.0 ... <= 0.16.2 | <= 0.5.1 | >= 2.4.1 |
|
53
|
-
0.
|
55
|
+
0.23.0 | 2.0 | >= 0.12.0 ... <= 0.17.0 | <= 0.5.1 | >= 2.4.1 |
|
54
56
|
|
55
57
|
<a name="swagger-spec" />
|
56
58
|
## Swagger-Spec
|
@@ -192,6 +194,9 @@ end
|
|
192
194
|
* [add_version](#add_version)
|
193
195
|
* [doc_version](#doc_version)
|
194
196
|
* [markdown](#markdown)
|
197
|
+
* [endpoint_auth_wrapper](#endpoint_auth_wrapper)
|
198
|
+
* [swagger_endpoint_guard](#swagger_endpoint_guard)
|
199
|
+
* [oauth_token](#oauth_token)
|
195
200
|
* [security_definitions](#security_definitions)
|
196
201
|
* [models](#models)
|
197
202
|
* [hide_documentation_path](#hide_documentation_path)
|
@@ -273,6 +278,33 @@ add_swagger_documentation \
|
|
273
278
|
markdown: GrapeSwagger::Markdown::RedcarpetAdapter.new
|
274
279
|
```
|
275
280
|
|
281
|
+
<a name="endpoint_auth_wrapper" />
|
282
|
+
#### endpoint_auth_wrapper:
|
283
|
+
Specify the middleware to use for securing endpoints.
|
284
|
+
|
285
|
+
```ruby
|
286
|
+
add_swagger_documentation \
|
287
|
+
endpoint_auth_wrapper: WineBouncer::OAuth2
|
288
|
+
```
|
289
|
+
|
290
|
+
<a name="swagger_endpoint_guard" />
|
291
|
+
#### swagger_endpoint_guard:
|
292
|
+
Specify the method and auth scopes, used by the middleware for securing endpoints.
|
293
|
+
|
294
|
+
```ruby
|
295
|
+
add_swagger_documentation \
|
296
|
+
swagger_endpoint_guard: 'oauth2 false'
|
297
|
+
```
|
298
|
+
|
299
|
+
<a name="oauth_token" />
|
300
|
+
#### oauth_token:
|
301
|
+
Specify the method to get the oauth_token, provided by the middleware.
|
302
|
+
|
303
|
+
```ruby
|
304
|
+
add_swagger_documentation \
|
305
|
+
oauth_token: 'doorkeeper_access_token'
|
306
|
+
```
|
307
|
+
|
276
308
|
<a name="security_definitions" />
|
277
309
|
#### security_definitions:
|
278
310
|
Specify the [Security Definitions Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#security-definitions-object)
|
@@ -518,6 +550,39 @@ end
|
|
518
550
|
}
|
519
551
|
```
|
520
552
|
|
553
|
+
#### Collection format of arrays
|
554
|
+
|
555
|
+
You can set the collection format of an array, using the documentation hash.
|
556
|
+
|
557
|
+
Collection format determines the format of the array if type array is used. Possible values are:
|
558
|
+
* csv - comma separated values foo,bar.
|
559
|
+
* ssv - space separated values foo bar.
|
560
|
+
* tsv - tab separated values foo\tbar.
|
561
|
+
* pipes - pipe separated values foo|bar.
|
562
|
+
* multi - corresponds to multiple parameter instances instead of multiple values for a single instance foo=bar&foo=baz. This is valid only for parameters in "query" or "formData".
|
563
|
+
|
564
|
+
```ruby
|
565
|
+
params do
|
566
|
+
requires :statuses, type: Array[String], documentation: { collectionFormat: 'multi' }
|
567
|
+
end
|
568
|
+
post :act do
|
569
|
+
...
|
570
|
+
end
|
571
|
+
```
|
572
|
+
|
573
|
+
```json
|
574
|
+
{
|
575
|
+
"in": "formData",
|
576
|
+
"name": "statuses",
|
577
|
+
"type": "array",
|
578
|
+
"items": {
|
579
|
+
"type": "string"
|
580
|
+
},
|
581
|
+
"collectionFormat": "multi",
|
582
|
+
"required": true
|
583
|
+
}
|
584
|
+
```
|
585
|
+
|
521
586
|
#### Multi types
|
522
587
|
|
523
588
|
By default when you set multi types, the first type is selected as swagger type
|
@@ -765,9 +830,78 @@ module API
|
|
765
830
|
end
|
766
831
|
```
|
767
832
|
|
833
|
+
<a name="oauth" />
|
834
|
+
## Securing the Swagger UI
|
835
|
+
|
836
|
+
|
837
|
+
The Swagger UI on Grape could be secured from unauthorized access using any middleware, which provides certain methods:
|
838
|
+
|
839
|
+
- a *before* method to be run in the Grape controller for authorization purpose;
|
840
|
+
- some guard method, which could receive as argument a string or an array of authorization scopes;
|
841
|
+
- a method which processes and returns the access token received in the HTTP request headers (usually in the 'HTTP_AUTHORIZATION' header).
|
842
|
+
|
843
|
+
Below are some examples of securing the Swagger UI on Grape installed along with Ruby on Rails:
|
844
|
+
|
845
|
+
- The WineBouncer and Doorkeeper gems are used in the examples;
|
846
|
+
- 'rails' and 'wine_bouncer' gems should be required prior to 'grape-swagger' in boot.rb;
|
847
|
+
- This works with a fresh PR to WineBouncer which is yet unmerged - [WineBouncer PR](https://github.com/antek-drzewiecki/wine_bouncer/pull/64).
|
848
|
+
|
849
|
+
This is how to configure the grape_swagger documentation:
|
850
|
+
|
851
|
+
```ruby
|
852
|
+
add_swagger_documentation base_path: '/',
|
853
|
+
title: 'My API',
|
854
|
+
doc_version: '0.0.1',
|
855
|
+
hide_documentation_path: true,
|
856
|
+
hide_format: true,
|
857
|
+
endpoint_auth_wrapper: WineBouncer::OAuth2, # This is the middleware for securing the Swagger UI
|
858
|
+
swagger_endpoint_guard: 'oauth2 false', # this is the guard method and scope
|
859
|
+
oauth_token: 'doorkeeper_access_token' # This is the method returning the access_token
|
860
|
+
```
|
861
|
+
|
862
|
+
The guard method should inject the Security Requirement Object into the endpoint's route settings (see Grape::DSL::Settings.route_setting method).
|
863
|
+
|
864
|
+
The 'oauth2 false' added to swagger_documentation is making the main Swagger endpoint protected with OAuth, i.e. it
|
865
|
+
is retreiving the access_token from the HTTP request, but the 'false' scope is for skipping authorization and showing
|
866
|
+
the UI for everyone. If the scope would be set to something else, like 'oauth2 admin', for example, than the UI
|
867
|
+
wouldn't be displayed at all to unauthorized users.
|
868
|
+
|
869
|
+
Further on, the guard could be used, where necessary, for endpoint access protection. Put it prior to the endpoint's method:
|
870
|
+
|
871
|
+
```ruby
|
872
|
+
resource :users do
|
873
|
+
oauth2 'read, write'
|
874
|
+
get do
|
875
|
+
render_users
|
876
|
+
end
|
877
|
+
|
878
|
+
oauth2 'admin'
|
879
|
+
post do
|
880
|
+
User.create!...
|
881
|
+
end
|
882
|
+
end
|
883
|
+
```
|
884
|
+
|
885
|
+
And, finally, if you want to not only restrict the access, but to completely hide the endpoint from unauthorized
|
886
|
+
users, you could pass a lambda to the :hidden key of a endpoint's description:
|
887
|
+
|
888
|
+
```ruby
|
889
|
+
not_admins = lambda { |token=nil| token.nil? || !User.find(token.resource_owner_id).admin? }
|
890
|
+
|
891
|
+
resource :users do
|
892
|
+
desc 'Create user', hidden: not_admins
|
893
|
+
oauth2 'admin'
|
894
|
+
post do
|
895
|
+
User.create!...
|
896
|
+
end
|
897
|
+
end
|
898
|
+
```
|
899
|
+
|
900
|
+
The lambda is checking whether the user is authenticated (if not, the token is nil by default), and has the admin
|
901
|
+
role - only admins can see this endpoint.
|
768
902
|
|
769
903
|
<a name="md_usage" />
|
770
|
-
|
904
|
+
## Markdown in Detail
|
771
905
|
|
772
906
|
The grape-swagger gem allows you to add an explanation in markdown in the detail field. Which would result in proper formatted markdown in Swagger UI.
|
773
907
|
Grape-swagger uses adapters for several markdown formatters. It includes adapters for [kramdown](http://kramdown.rubyforge.org) (kramdown [syntax](http://kramdown.rubyforge.org/syntax.html)) and [redcarpet](https://github.com/vmg/redcarpet).
|
@@ -961,19 +1095,20 @@ route_setting :x_def, [{ for: 422, other: 'stuff' }, { for: 200, some: 'stuff' }
|
|
961
1095
|
```
|
962
1096
|
|
963
1097
|
<a="example" />
|
964
|
-
|
1098
|
+
## Example
|
965
1099
|
|
966
1100
|
Go into example directory and run it: `$ bundle exec rackup`
|
967
1101
|
go to: `http://localhost:9292/swagger_doc` to get it
|
968
1102
|
|
969
1103
|
For request examples load the [postman file]()
|
970
|
-
|
1104
|
+
|
1105
|
+
#### Grouping the API list using Namespace
|
971
1106
|
|
972
1107
|
Use namespace for grouping APIs
|
973
1108
|
|
974
1109
|
![grape-swagger-v2-new-corrected](https://cloud.githubusercontent.com/assets/1027590/13516020/979cfefa-e1f9-11e5-9624-f4a6b17a3c8a.png)
|
975
1110
|
|
976
|
-
|
1111
|
+
#### Example Code
|
977
1112
|
|
978
1113
|
```ruby
|
979
1114
|
class NamespaceApi < Grape::API
|
@@ -1005,6 +1140,38 @@ end
|
|
1005
1140
|
|
1006
1141
|
```
|
1007
1142
|
|
1143
|
+
|
1144
|
+
<a name="rake" />
|
1145
|
+
## Rake Tasks
|
1146
|
+
|
1147
|
+
Add these lines to your Rakefile, and initialize the Task class with your Api class – be sure your Api class is available.
|
1148
|
+
|
1149
|
+
```ruby
|
1150
|
+
require 'grape-swagger/rake/oapi_tasks'
|
1151
|
+
GrapeSwagger::Rake::OapiTasks.new(::Api::Base)
|
1152
|
+
```
|
1153
|
+
|
1154
|
+
#### OpenApi/Swagger Documentation
|
1155
|
+
|
1156
|
+
```
|
1157
|
+
rake oapi:fetch
|
1158
|
+
params:
|
1159
|
+
- store={ true | file_name } – save as JSON (optional)
|
1160
|
+
- resource=resource_name – get only for this one (optional)
|
1161
|
+
```
|
1162
|
+
|
1163
|
+
#### OpenApi/Swagger Validation
|
1164
|
+
|
1165
|
+
**requires**: `npm` and `swagger-cli` to be installed
|
1166
|
+
|
1167
|
+
|
1168
|
+
```
|
1169
|
+
rake oapi:validate
|
1170
|
+
params:
|
1171
|
+
- resource=resource_name – get only for this one (optional)
|
1172
|
+
```
|
1173
|
+
|
1174
|
+
|
1008
1175
|
## Contributing to grape-swagger
|
1009
1176
|
|
1010
1177
|
See [CONTRIBUTING](CONTRIBUTING.md).
|
data/lib/grape-swagger.rb
CHANGED
@@ -18,6 +18,7 @@ module GrapeSwagger
|
|
18
18
|
@model_parsers ||= GrapeSwagger::ModelParsers.new
|
19
19
|
end
|
20
20
|
end
|
21
|
+
autoload :Rake, 'grape-swagger/rake/oapi_tasks'
|
21
22
|
end
|
22
23
|
|
23
24
|
module Grape
|
@@ -31,6 +32,11 @@ module Grape
|
|
31
32
|
version_for(options)
|
32
33
|
options = { target_class: self }.merge(options)
|
33
34
|
@target_class = options[:target_class]
|
35
|
+
auth_wrapper = options[:endpoint_auth_wrapper]
|
36
|
+
|
37
|
+
if auth_wrapper && auth_wrapper.method_defined?(:before) && !middleware.flatten.include?(auth_wrapper)
|
38
|
+
use auth_wrapper
|
39
|
+
end
|
34
40
|
|
35
41
|
documentation_class.setup(options)
|
36
42
|
mount(documentation_class)
|
@@ -80,7 +86,9 @@ module Grape
|
|
80
86
|
end
|
81
87
|
# use the full namespace here (not the latest level only)
|
82
88
|
# and strip leading slash
|
83
|
-
|
89
|
+
mount_path = (endpoint.namespace_stackable(:mount_path) || []).join('/')
|
90
|
+
full_namespace = (mount_path + endpoint.namespace).sub(/\/{2,}/, '/').sub(/^\//, '')
|
91
|
+
@target_class.combined_namespaces[full_namespace] = ns if ns
|
84
92
|
|
85
93
|
combine_namespaces(endpoint.options[:app]) if endpoint.options[:app]
|
86
94
|
end
|
@@ -31,37 +31,38 @@ module GrapeSwagger
|
|
31
31
|
# options could be set on #add_swagger_documentation call,
|
32
32
|
# for available options see #defaults
|
33
33
|
target_class = options[:target_class]
|
34
|
-
|
35
|
-
|
34
|
+
guard = options[:swagger_endpoint_guard]
|
35
|
+
formatter = options[:format]
|
36
36
|
|
37
37
|
class_variables_from(options)
|
38
38
|
|
39
39
|
[:format, :default_format, :default_error_formatter].each do |method|
|
40
|
-
send(method,
|
41
|
-
end if
|
42
|
-
# getting of the whole swagger2.0 spec file
|
43
|
-
desc api_doc.delete(:desc), api_doc
|
44
|
-
get mount_path do
|
45
|
-
header['Access-Control-Allow-Origin'] = '*'
|
46
|
-
header['Access-Control-Request-Method'] = '*'
|
40
|
+
send(method, formatter)
|
41
|
+
end if formatter
|
47
42
|
|
48
|
-
|
43
|
+
send(guard.split.first.to_sym, *guard.split(/[\s,]+/).drop(1)) unless guard.nil?
|
44
|
+
|
45
|
+
output_path_definitions = proc do |combi_routes, endpoint|
|
46
|
+
output = endpoint.swagger_object(
|
49
47
|
target_class,
|
50
|
-
request,
|
48
|
+
endpoint.request,
|
51
49
|
options
|
52
50
|
)
|
53
51
|
|
54
|
-
|
55
|
-
paths, definitions = path_and_definition_objects(target_routes, options)
|
52
|
+
paths, definitions = endpoint.path_and_definition_objects(combi_routes, options)
|
56
53
|
output[:paths] = paths unless paths.blank?
|
57
54
|
output[:definitions] = definitions unless definitions.blank?
|
58
55
|
|
59
56
|
output
|
60
57
|
end
|
61
58
|
|
62
|
-
|
63
|
-
|
64
|
-
|
59
|
+
get mount_path do
|
60
|
+
header['Access-Control-Allow-Origin'] = '*'
|
61
|
+
header['Access-Control-Request-Method'] = '*'
|
62
|
+
|
63
|
+
output_path_definitions.call(target_class.combined_namespace_routes, self)
|
64
|
+
end
|
65
|
+
|
65
66
|
params do
|
66
67
|
requires :name, type: String, desc: 'Resource name of mounted API'
|
67
68
|
optional :locale, type: Symbol, desc: 'Locale of API documentation'
|
@@ -72,18 +73,7 @@ module GrapeSwagger
|
|
72
73
|
combined_routes = target_class.combined_namespace_routes[params[:name]]
|
73
74
|
error!({ error: 'named resource not exist' }, 400) if combined_routes.nil?
|
74
75
|
|
75
|
-
|
76
|
-
target_class,
|
77
|
-
request,
|
78
|
-
options
|
79
|
-
)
|
80
|
-
|
81
|
-
target_routes = { params[:name] => combined_routes }
|
82
|
-
paths, definitions = path_and_definition_objects(target_routes, options)
|
83
|
-
output[:paths] = paths unless paths.blank?
|
84
|
-
output[:definitions] = definitions unless definitions.blank?
|
85
|
-
|
86
|
-
output
|
76
|
+
output_path_definitions.call({ params[:name] => combined_routes }, self)
|
87
77
|
end
|
88
78
|
end
|
89
79
|
|
@@ -104,7 +94,10 @@ module GrapeSwagger
|
|
104
94
|
authorizations: nil,
|
105
95
|
security_definitions: nil,
|
106
96
|
api_documentation: { desc: 'Swagger compatible API description' },
|
107
|
-
specific_api_documentation: { desc: 'Swagger compatible API description for specific API' }
|
97
|
+
specific_api_documentation: { desc: 'Swagger compatible API description for specific API' },
|
98
|
+
endpoint_auth_wrapper: nil,
|
99
|
+
swagger_endpoint_guard: nil,
|
100
|
+
oauth_token: nil
|
108
101
|
}
|
109
102
|
end
|
110
103
|
|
@@ -66,6 +66,7 @@ module GrapeSwagger
|
|
66
66
|
param_type = value_type[:documentation][:param_type]
|
67
67
|
doc_type = value_type[:documentation][:type]
|
68
68
|
type = GrapeSwagger::DocMethods::DataType.mapping(doc_type) if doc_type && !DataType.request_primitive?(doc_type)
|
69
|
+
collection_format = value_type[:documentation][:collectionFormat]
|
69
70
|
end
|
70
71
|
|
71
72
|
array_items = {
|
@@ -76,6 +77,7 @@ module GrapeSwagger
|
|
76
77
|
@parsed_param[:in] = param_type || 'formData'
|
77
78
|
@parsed_param[:items] = array_items
|
78
79
|
@parsed_param[:type] = 'array'
|
80
|
+
@parsed_param[:collectionFormat] = collection_format if %w(csv ssv tsv pipes multi).include?(collection_format)
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require 'active_support/core_ext/string/inflections.rb'
|
3
5
|
|
@@ -84,7 +86,7 @@ module Grape
|
|
84
86
|
# path object
|
85
87
|
def path_item(routes, options)
|
86
88
|
routes.each do |route|
|
87
|
-
next if hidden?(route)
|
89
|
+
next if hidden?(route, options)
|
88
90
|
|
89
91
|
@item, path = GrapeSwagger::DocMethods::PathString.build(route, options)
|
90
92
|
@entity = route.entity || route.options[:success]
|
@@ -108,6 +110,7 @@ module Grape
|
|
108
110
|
method[:produces] = produces_object(route, options[:produces] || options[:format])
|
109
111
|
method[:consumes] = consumes_object(route, options[:format])
|
110
112
|
method[:parameters] = params_object(route)
|
113
|
+
method[:security] = security_object(route)
|
111
114
|
method[:responses] = response_object(route, options[:markdown])
|
112
115
|
method[:tags] = tag_object(route)
|
113
116
|
method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
|
@@ -116,6 +119,10 @@ module Grape
|
|
116
119
|
[route.request_method.downcase.to_sym, method]
|
117
120
|
end
|
118
121
|
|
122
|
+
def security_object(route)
|
123
|
+
route.options[:security] if route.options.key?(:security)
|
124
|
+
end
|
125
|
+
|
119
126
|
def summary_object(route)
|
120
127
|
summary = route.options[:desc] if route.options.key?(:desc)
|
121
128
|
summary = route.description if route.description.present?
|
@@ -215,15 +222,17 @@ module Grape
|
|
215
222
|
declared_params = route.settings[:declared_params] if route.settings[:declared_params].present?
|
216
223
|
required, exposed = route.params.partition { |x| x.first.is_a? String }
|
217
224
|
required = GrapeSwagger::DocMethods::Headers.parse(route) + required unless route.headers.nil?
|
225
|
+
|
218
226
|
default_type(required)
|
219
227
|
default_type(exposed)
|
220
228
|
|
221
|
-
unless declared_params.nil? && route.headers.nil?
|
222
|
-
|
223
|
-
|
229
|
+
request_params = unless declared_params.nil? && route.headers.nil?
|
230
|
+
parse_request_params(required)
|
231
|
+
end || {}
|
232
|
+
|
233
|
+
request_params = route.params.merge(request_params) if route.params.present? && !route.settings[:declared_params].present?
|
224
234
|
|
225
|
-
|
226
|
-
request_params || {}
|
235
|
+
request_params
|
227
236
|
end
|
228
237
|
|
229
238
|
def default_type(params)
|
@@ -279,13 +288,23 @@ module Grape
|
|
279
288
|
end
|
280
289
|
|
281
290
|
def model_name(name)
|
282
|
-
name.respond_to?(:
|
291
|
+
if name.respond_to?(:entity_name)
|
292
|
+
name.entity_name
|
293
|
+
elsif name.to_s.end_with?('Entity', 'Entities')
|
294
|
+
length = 0
|
295
|
+
name.to_s.split('::')[0..-2].reverse.take_while do |x|
|
296
|
+
length += x.length
|
297
|
+
length < 42
|
298
|
+
end.reverse.join
|
299
|
+
else
|
300
|
+
name.name.demodulize.camelize
|
301
|
+
end
|
283
302
|
end
|
284
303
|
|
285
|
-
def hidden?(route)
|
304
|
+
def hidden?(route, options)
|
286
305
|
route_hidden = route.options[:hidden]
|
287
|
-
|
288
|
-
route_hidden
|
306
|
+
return route_hidden unless route_hidden.is_a?(Proc)
|
307
|
+
options[:oauth_token] ? route_hidden.call(send(options[:oauth_token].to_sym)) : route_hidden.call
|
289
308
|
end
|
290
309
|
|
291
310
|
def public_parameter?(param)
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
require 'rack/test'
|
4
|
+
|
5
|
+
module GrapeSwagger
|
6
|
+
module Rake
|
7
|
+
class OapiTasks < ::Rake::TaskLib
|
8
|
+
include Rack::Test::Methods
|
9
|
+
|
10
|
+
attr_reader :oapi
|
11
|
+
attr_reader :api_class
|
12
|
+
|
13
|
+
def initialize(api_class)
|
14
|
+
super()
|
15
|
+
|
16
|
+
@api_class = api_class
|
17
|
+
define_tasks
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def define_tasks
|
23
|
+
namespace :oapi do
|
24
|
+
fetch
|
25
|
+
validate
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# tasks
|
30
|
+
#
|
31
|
+
# get swagger/OpenAPI documentation
|
32
|
+
def fetch
|
33
|
+
desc 'generates OpenApi documentation …
|
34
|
+
params (usage: key=value):
|
35
|
+
store – save as JSON file, default: false (optional)
|
36
|
+
resource - if given only for that it would be generated (optional)'
|
37
|
+
task fetch: :environment do
|
38
|
+
make_request
|
39
|
+
|
40
|
+
save_to_file? ? File.write(file, @oapi) : $stdout.print(@oapi)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# validates swagger/OpenAPI documentation
|
45
|
+
def validate
|
46
|
+
desc 'validates the generated OpenApi file …
|
47
|
+
params (usage: key=value):
|
48
|
+
resource - if given only for that it would be generated (optional)'
|
49
|
+
task validate: :environment do
|
50
|
+
ENV['store'] = 'true'
|
51
|
+
::Rake::Task['oapi:fetch'].invoke
|
52
|
+
exit if error?
|
53
|
+
|
54
|
+
output = system "swagger validate #{file}"
|
55
|
+
|
56
|
+
$stdout.puts 'install swagger-cli with `npm install swagger-cli -g`' if output.nil?
|
57
|
+
FileUtils.rm(file)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# helper methods
|
62
|
+
#
|
63
|
+
def make_request
|
64
|
+
get url_for
|
65
|
+
last_response
|
66
|
+
@oapi = JSON.pretty_generate(
|
67
|
+
JSON.parse(
|
68
|
+
last_response.body, symolize_names: true
|
69
|
+
)
|
70
|
+
) + "\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
def url_for
|
74
|
+
oapi_route = api_class.routes[-2]
|
75
|
+
path = oapi_route.path.sub(/\(\.\w+\)$/, '').sub(/\(\.:\w+\)$/, '')
|
76
|
+
path.sub!(':version', oapi_route.version.to_s)
|
77
|
+
|
78
|
+
[path, ENV['resource']].join('/').chomp('/')
|
79
|
+
end
|
80
|
+
|
81
|
+
def save_to_file?
|
82
|
+
ENV['store'].present? && !error?
|
83
|
+
end
|
84
|
+
|
85
|
+
def error?
|
86
|
+
JSON.parse(@oapi).keys.first == 'error'
|
87
|
+
end
|
88
|
+
|
89
|
+
def file
|
90
|
+
name = ENV['store'] == 'true' || ENV['store'].blank? ? 'swagger_doc.json' : ENV['store']
|
91
|
+
File.join(Dir.getwd, name)
|
92
|
+
end
|
93
|
+
|
94
|
+
def app
|
95
|
+
api_class.new
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'grape-entity'
|
3
|
+
require 'grape-swagger-entity'
|
4
|
+
|
5
|
+
describe 'definition names' do
|
6
|
+
before :all do
|
7
|
+
module TestDefinition
|
8
|
+
module DummyEntities
|
9
|
+
module WithVeryLongName
|
10
|
+
module AnotherGroupingModule
|
11
|
+
class Class1
|
12
|
+
class Entity < Grape::Entity
|
13
|
+
expose :one_thing
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Class2
|
18
|
+
class Entity < Grape::Entity
|
19
|
+
expose :another_thing
|
20
|
+
|
21
|
+
def self.entity_name
|
22
|
+
'FooKlass'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class NameApi < Grape::API
|
31
|
+
add_swagger_documentation models: [
|
32
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class1::Entity,
|
33
|
+
DummyEntities::WithVeryLongName::AnotherGroupingModule::Class2::Entity
|
34
|
+
]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
let(:app) { TestDefinition::NameApi }
|
40
|
+
|
41
|
+
subject do
|
42
|
+
get '/swagger_doc'
|
43
|
+
JSON.parse(last_response.body)['definitions']
|
44
|
+
end
|
45
|
+
|
46
|
+
specify { expect(subject).to include 'AnotherGroupingModuleClass1' }
|
47
|
+
specify { expect(subject).to include 'FooKlass' }
|
48
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe GrapeSwagger::Rake::OapiTasks do
|
4
|
+
let(:api) do
|
5
|
+
item = Class.new(Grape::API) do
|
6
|
+
version 'v1', using: :path
|
7
|
+
|
8
|
+
resource :item do
|
9
|
+
get '/'
|
10
|
+
end
|
11
|
+
|
12
|
+
resource :otherItem do
|
13
|
+
get '/'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
Class.new(Grape::API) do
|
18
|
+
prefix :api
|
19
|
+
mount item
|
20
|
+
add_swagger_documentation add_version: true
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { described_class.new(api) }
|
25
|
+
|
26
|
+
describe '#make_request' do
|
27
|
+
describe 'complete documentation' do
|
28
|
+
before do
|
29
|
+
subject.send(:make_request)
|
30
|
+
end
|
31
|
+
|
32
|
+
describe 'not storing' do
|
33
|
+
it 'has no error' do
|
34
|
+
expect(subject.send(:error?)).to be false
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'does not allow to save' do
|
38
|
+
expect(subject.send(:save_to_file?)).to be false
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'requests doc url' do
|
42
|
+
expect(subject.send(:url_for)).to eql '/api/swagger_doc'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'store it' do
|
47
|
+
before { ENV['store'] = 'true' }
|
48
|
+
after { ENV.delete('store') }
|
49
|
+
|
50
|
+
it 'allows to save' do
|
51
|
+
expect(subject.send(:save_to_file?)).to be true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'documentation for resource' do
|
57
|
+
before do
|
58
|
+
ENV['resource'] = resource
|
59
|
+
subject.send(:make_request)
|
60
|
+
end
|
61
|
+
|
62
|
+
let(:response) { JSON.parse(subject.send(:make_request)) }
|
63
|
+
|
64
|
+
after { ENV.delete('resource') }
|
65
|
+
|
66
|
+
describe 'valid name' do
|
67
|
+
let(:resource) { 'otherItem' }
|
68
|
+
|
69
|
+
it 'has no error' do
|
70
|
+
expect(subject.send(:error?)).to be false
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'requests doc url' do
|
74
|
+
expect(subject.send(:url_for)).to eql "/api/swagger_doc/#{resource}"
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'has only one resource path' do
|
78
|
+
expect(response['paths'].length).to eql 1
|
79
|
+
expect(response['paths'].keys.first).to end_with resource
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'wrong name' do
|
84
|
+
let(:resource) { 'foo' }
|
85
|
+
|
86
|
+
it 'has error' do
|
87
|
+
expect(subject.send(:error?)).to be true
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'empty name' do
|
92
|
+
let(:resource) { nil }
|
93
|
+
|
94
|
+
it 'has no error' do
|
95
|
+
expect(subject.send(:error?)).to be false
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'returns complete doc' do
|
99
|
+
expect(response['paths'].length).to eql 2
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#file' do
|
106
|
+
describe 'no store given' do
|
107
|
+
it 'returns swagger_doc.json' do
|
108
|
+
expect(subject.send(:file)).to end_with 'swagger_doc.json'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe 'store given' do
|
113
|
+
after { ENV.delete('store') }
|
114
|
+
|
115
|
+
describe 'boolean true' do
|
116
|
+
before { ENV['store'] = 'true' }
|
117
|
+
|
118
|
+
it 'returns swagger_doc.json' do
|
119
|
+
expect(subject.send(:file)).to end_with 'swagger_doc.json'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
describe 'name given' do
|
124
|
+
let(:name) { 'oapi_doc.json' }
|
125
|
+
before { ENV['store'] = name }
|
126
|
+
|
127
|
+
it 'returns swagger_doc.json' do
|
128
|
+
expect(subject.send(:file)).to end_with name
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -39,6 +39,8 @@ describe 'body parameter definitions' do
|
|
39
39
|
'body_param' => { 'type' => 'string', 'description' => 'param' },
|
40
40
|
'body_type_as_const_param' => { 'type' => 'string', 'description' => 'string_param' }
|
41
41
|
)
|
42
|
+
|
43
|
+
expect(subject['paths']['/endpoint']['post']['parameters'].any? { |p| p['name'] == 'XAuthToken' && p['in'] == 'header' }).to eql(true)
|
42
44
|
end
|
43
45
|
end
|
44
46
|
end
|
@@ -2,8 +2,6 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe 'details' do
|
4
4
|
describe 'details, pass markdown with redcarpet even with nil description and detail', unless: RUBY_PLATFORM.eql?('java') do
|
5
|
-
include_context 'the api entities'
|
6
|
-
|
7
5
|
before :all do
|
8
6
|
module TheApi
|
9
7
|
class GfmRcDetailApi < Grape::API
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
class SampleAuth < Grape::Middleware::Base
|
6
|
+
module AuthMethods
|
7
|
+
attr_accessor :access_token
|
8
|
+
|
9
|
+
def protected_endpoint=(protected)
|
10
|
+
@protected_endpoint = protected
|
11
|
+
end
|
12
|
+
|
13
|
+
def protected_endpoint?
|
14
|
+
@protected_endpoint || false
|
15
|
+
end
|
16
|
+
|
17
|
+
def access_token
|
18
|
+
@_access_token
|
19
|
+
end
|
20
|
+
|
21
|
+
def access_token=(token)
|
22
|
+
@_access_token = token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def context
|
27
|
+
env['api.endpoint']
|
28
|
+
end
|
29
|
+
|
30
|
+
def before
|
31
|
+
context.extend(SampleAuth::AuthMethods)
|
32
|
+
context.protected_endpoint = context.options[:route_options][:auth].present?
|
33
|
+
|
34
|
+
return unless context.protected_endpoint?
|
35
|
+
scopes = context.options[:route_options][:auth][:scopes].map(&:to_sym)
|
36
|
+
authorize!(*scopes) unless scopes.include? :false
|
37
|
+
context.access_token = env['HTTP_AUTHORIZATION']
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Extension
|
42
|
+
def sample_auth(*scopes)
|
43
|
+
description = route_setting(:description) || route_setting(:description, {})
|
44
|
+
description[:auth] = { scopes: scopes }
|
45
|
+
end
|
46
|
+
|
47
|
+
Grape::API.extend self
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'a guarded api endpoint' do
|
51
|
+
before :all do
|
52
|
+
class GuardedMountedApi < Grape::API
|
53
|
+
access_token_valid = proc { |token = nil| token.nil? || token != '12345' }
|
54
|
+
|
55
|
+
desc 'Show endpoint if authenticated', hidden: access_token_valid
|
56
|
+
get '/auth' do
|
57
|
+
{ foo: 'bar' }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class GuardedApi < Grape::API
|
62
|
+
mount GuardedMountedApi
|
63
|
+
add_swagger_documentation endpoint_auth_wrapper: SampleAuth,
|
64
|
+
swagger_endpoint_guard: 'sample_auth false',
|
65
|
+
oauth_token: 'access_token'
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def app
|
70
|
+
GuardedApi
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when a correct token is passed with the request' do
|
74
|
+
subject do
|
75
|
+
get '/swagger_doc.json', {}, 'HTTP_AUTHORIZATION' => '12345'
|
76
|
+
JSON.parse(last_response.body)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'retrieves swagger-documentation for the endpoint' do
|
80
|
+
expect(subject).to eq(
|
81
|
+
'info' => { 'title' => 'API title', 'version' => '0.0.1' },
|
82
|
+
'swagger' => '2.0',
|
83
|
+
'produces' => ['application/xml', 'application/json', 'application/octet-stream', 'text/plain'],
|
84
|
+
'host' => 'example.org',
|
85
|
+
'paths' => {
|
86
|
+
'/auth' => {
|
87
|
+
'get' => {
|
88
|
+
'summary' => 'Show endpoint if authenticated',
|
89
|
+
'description' => 'Show endpoint if authenticated',
|
90
|
+
'produces' => ['application/json'],
|
91
|
+
'tags' => ['auth'],
|
92
|
+
'operationId' => 'getAuth',
|
93
|
+
'responses' => { '200' => { 'description' => 'Show endpoint if authenticated' } }
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'when a bad token is passed with the request' do
|
102
|
+
subject do
|
103
|
+
get '/swagger_doc.json', {}, 'HTTP_AUTHORIZATION' => '123456'
|
104
|
+
JSON.parse(last_response.body)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'does not retrieve swagger-documentation for the endpoint - only the info_object' do
|
108
|
+
expect(subject).to eq(
|
109
|
+
'info' => { 'title' => 'API title', 'version' => '0.0.1' },
|
110
|
+
'swagger' => '2.0',
|
111
|
+
'produces' => ['application/xml', 'application/json', 'application/octet-stream', 'text/plain'],
|
112
|
+
'host' => 'example.org'
|
113
|
+
)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/spec/swagger_v2/host.rb
CHANGED
@@ -64,4 +64,56 @@ describe 'namespace' do
|
|
64
64
|
expect(subject['description']).to eql('Description for aspace')
|
65
65
|
end
|
66
66
|
end
|
67
|
+
|
68
|
+
context 'mounted under a route' do
|
69
|
+
def app
|
70
|
+
namespaced_api = Class.new(Grape::API) do
|
71
|
+
namespace :bspace do
|
72
|
+
get '/', desc: 'Description for aspace'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
Class.new(Grape::API) do
|
77
|
+
mount namespaced_api => '/mounted'
|
78
|
+
add_swagger_documentation format: :json
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
subject do
|
83
|
+
get '/swagger_doc'
|
84
|
+
JSON.parse(last_response.body)['paths']['/mounted/bspace']['get']
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'shows the namespace description in the json spec' do
|
88
|
+
expect(subject['description']).to eql('Description for aspace')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'arbitrary mounting' do
|
93
|
+
def app
|
94
|
+
inner_namespaced_api = Class.new(Grape::API) do
|
95
|
+
namespace :bspace do
|
96
|
+
get '/', desc: 'Description for aspace'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
outer_namespaced_api = Class.new(Grape::API) do
|
101
|
+
mount inner_namespaced_api => '/mounted'
|
102
|
+
end
|
103
|
+
|
104
|
+
Class.new(Grape::API) do
|
105
|
+
mount outer_namespaced_api => '/'
|
106
|
+
add_swagger_documentation format: :json
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
subject do
|
111
|
+
get '/swagger_doc'
|
112
|
+
JSON.parse(last_response.body)['paths']['/mounted/bspace']['get']
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'shows the namespace description in the json spec' do
|
116
|
+
expect(subject['description']).to eql('Description for aspace')
|
117
|
+
end
|
118
|
+
end
|
67
119
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Group Array Params, using collection format' do
|
4
|
+
def app
|
5
|
+
Class.new(Grape::API) do
|
6
|
+
format :json
|
7
|
+
|
8
|
+
params do
|
9
|
+
optional :array_of_strings, type: Array[String], desc: 'array in csv collection format'
|
10
|
+
end
|
11
|
+
|
12
|
+
get '/array_of_strings_without_collection_format' do
|
13
|
+
{ 'declared_params' => declared(params) }
|
14
|
+
end
|
15
|
+
|
16
|
+
params do
|
17
|
+
optional :array_of_strings, type: Array[String], desc: 'array in multi collection format', documentation: { collectionFormat: 'multi' }
|
18
|
+
end
|
19
|
+
|
20
|
+
get '/array_of_strings_multi_collection_format' do
|
21
|
+
{ 'declared_params' => declared(params) }
|
22
|
+
end
|
23
|
+
|
24
|
+
params do
|
25
|
+
optional :array_of_strings, type: Array[String], documentation: { collectionFormat: 'foo' }
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/array_of_strings_invalid_collection_format' do
|
29
|
+
{ 'declared_params' => declared(params) }
|
30
|
+
end
|
31
|
+
|
32
|
+
add_swagger_documentation
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'documentation for array parameter in default csv collectionFormat' do
|
37
|
+
subject do
|
38
|
+
get '/swagger_doc/array_of_strings_without_collection_format'
|
39
|
+
JSON.parse(last_response.body)
|
40
|
+
end
|
41
|
+
|
42
|
+
specify do
|
43
|
+
expect(subject['paths']['/array_of_strings_without_collection_format']['get']['parameters']).to eql(
|
44
|
+
[
|
45
|
+
{ 'in' => 'formData', 'name' => 'array_of_strings', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false, 'description' => 'array in csv collection format' }
|
46
|
+
]
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'documentation for array parameters in multi collectionFormat set from documentation' do
|
52
|
+
subject do
|
53
|
+
get '/swagger_doc/array_of_strings_multi_collection_format'
|
54
|
+
JSON.parse(last_response.body)
|
55
|
+
end
|
56
|
+
|
57
|
+
specify do
|
58
|
+
expect(subject['paths']['/array_of_strings_multi_collection_format']['get']['parameters']).to eql(
|
59
|
+
[
|
60
|
+
{ 'in' => 'formData', 'name' => 'array_of_strings', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false, 'collectionFormat' => 'multi', 'description' => 'array in multi collection format' }
|
61
|
+
]
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'documentation for array parameters with collectionFormat set to invalid option' do
|
67
|
+
subject do
|
68
|
+
get '/swagger_doc/array_of_strings_invalid_collection_format'
|
69
|
+
JSON.parse(last_response.body)
|
70
|
+
end
|
71
|
+
|
72
|
+
specify do
|
73
|
+
expect(subject['paths']['/array_of_strings_invalid_collection_format']['get']['parameters']).to eql(
|
74
|
+
[
|
75
|
+
{ 'in' => 'formData', 'name' => 'array_of_strings', 'type' => 'array', 'items' => { 'type' => 'string' }, 'required' => false }
|
76
|
+
]
|
77
|
+
)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'security requirement on endpoint method' do
|
4
|
+
def app
|
5
|
+
Class.new(Grape::API) do
|
6
|
+
desc 'Endpoint with security requirement', security: [oauth_pets: ['read:pets', 'write:pets']]
|
7
|
+
get '/with_security' do
|
8
|
+
{ foo: 'bar' }
|
9
|
+
end
|
10
|
+
|
11
|
+
add_swagger_documentation
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
subject do
|
16
|
+
get '/swagger_doc.json'
|
17
|
+
JSON.parse(last_response.body)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'defines the security requirement on the endpoint method' do
|
21
|
+
expect(subject['paths']['/with_security']['get']['security']).to eql ['oauth_pets' => ['read:pets', 'write:pets']]
|
22
|
+
end
|
23
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: grape-swagger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.24.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Vandecasteele
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: grape
|
@@ -255,13 +255,16 @@ files:
|
|
255
255
|
- lib/grape-swagger/markdown/kramdown_adapter.rb
|
256
256
|
- lib/grape-swagger/markdown/redcarpet_adapter.rb
|
257
257
|
- lib/grape-swagger/model_parsers.rb
|
258
|
+
- lib/grape-swagger/rake/oapi_tasks.rb
|
258
259
|
- lib/grape-swagger/version.rb
|
259
260
|
- spec/issues/403_versions_spec.rb
|
261
|
+
- spec/issues/430_entity_definitions_spec.rb
|
260
262
|
- spec/lib/data_type_spec.rb
|
261
263
|
- spec/lib/endpoint_spec.rb
|
262
264
|
- spec/lib/extensions_spec.rb
|
263
265
|
- spec/lib/model_parsers_spec.rb
|
264
266
|
- spec/lib/move_params_spec.rb
|
267
|
+
- spec/lib/oapi_tasks_spec.rb
|
265
268
|
- spec/lib/operation_id_spec.rb
|
266
269
|
- spec/lib/optional_object_spec.rb
|
267
270
|
- spec/lib/path_string_spec.rb
|
@@ -304,6 +307,7 @@ files:
|
|
304
307
|
- spec/swagger_v2/float_api_spec.rb
|
305
308
|
- spec/swagger_v2/form_params_spec.rb
|
306
309
|
- spec/swagger_v2/grape-swagger_spec.rb
|
310
|
+
- spec/swagger_v2/guarded_endpoint_spec.rb
|
307
311
|
- spec/swagger_v2/hide_api_spec.rb
|
308
312
|
- spec/swagger_v2/host.rb
|
309
313
|
- spec/swagger_v2/mounted_target_class_spec.rb
|
@@ -314,10 +318,12 @@ files:
|
|
314
318
|
- spec/swagger_v2/param_multi_type_spec.rb
|
315
319
|
- spec/swagger_v2/param_type_spec.rb
|
316
320
|
- spec/swagger_v2/param_values_spec.rb
|
321
|
+
- spec/swagger_v2/params_array_collection_fromat_spec.rb
|
317
322
|
- spec/swagger_v2/params_array_spec.rb
|
318
323
|
- spec/swagger_v2/params_hash_spec.rb
|
319
324
|
- spec/swagger_v2/params_nested_spec.rb
|
320
325
|
- spec/swagger_v2/reference_entity.rb
|
326
|
+
- spec/swagger_v2/security_requirement_spec.rb
|
321
327
|
- spec/swagger_v2/simple_mounted_api_spec.rb
|
322
328
|
- spec/version_spec.rb
|
323
329
|
homepage: https://github.com/ruby-grape/grape-swagger
|
@@ -340,18 +346,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
340
346
|
version: '0'
|
341
347
|
requirements: []
|
342
348
|
rubyforge_project:
|
343
|
-
rubygems_version: 2.6.
|
349
|
+
rubygems_version: 2.6.6
|
344
350
|
signing_key:
|
345
351
|
specification_version: 4
|
346
352
|
summary: A simple way to add auto generated documentation to your Grape API that can
|
347
353
|
be displayed with Swagger.
|
348
354
|
test_files:
|
349
355
|
- spec/issues/403_versions_spec.rb
|
356
|
+
- spec/issues/430_entity_definitions_spec.rb
|
350
357
|
- spec/lib/data_type_spec.rb
|
351
358
|
- spec/lib/endpoint_spec.rb
|
352
359
|
- spec/lib/extensions_spec.rb
|
353
360
|
- spec/lib/model_parsers_spec.rb
|
354
361
|
- spec/lib/move_params_spec.rb
|
362
|
+
- spec/lib/oapi_tasks_spec.rb
|
355
363
|
- spec/lib/operation_id_spec.rb
|
356
364
|
- spec/lib/optional_object_spec.rb
|
357
365
|
- spec/lib/path_string_spec.rb
|
@@ -394,6 +402,7 @@ test_files:
|
|
394
402
|
- spec/swagger_v2/float_api_spec.rb
|
395
403
|
- spec/swagger_v2/form_params_spec.rb
|
396
404
|
- spec/swagger_v2/grape-swagger_spec.rb
|
405
|
+
- spec/swagger_v2/guarded_endpoint_spec.rb
|
397
406
|
- spec/swagger_v2/hide_api_spec.rb
|
398
407
|
- spec/swagger_v2/host.rb
|
399
408
|
- spec/swagger_v2/mounted_target_class_spec.rb
|
@@ -404,9 +413,11 @@ test_files:
|
|
404
413
|
- spec/swagger_v2/param_multi_type_spec.rb
|
405
414
|
- spec/swagger_v2/param_type_spec.rb
|
406
415
|
- spec/swagger_v2/param_values_spec.rb
|
416
|
+
- spec/swagger_v2/params_array_collection_fromat_spec.rb
|
407
417
|
- spec/swagger_v2/params_array_spec.rb
|
408
418
|
- spec/swagger_v2/params_hash_spec.rb
|
409
419
|
- spec/swagger_v2/params_nested_spec.rb
|
410
420
|
- spec/swagger_v2/reference_entity.rb
|
421
|
+
- spec/swagger_v2/security_requirement_spec.rb
|
411
422
|
- spec/swagger_v2/simple_mounted_api_spec.rb
|
412
423
|
- spec/version_spec.rb
|