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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1c9531be292e7a5a8d3ee086291e248f42f13457
4
- data.tar.gz: 8f7cea40f42d1bb5a474f3468000c837eb540699
3
+ metadata.gz: 99ac4d378547c6998e6c712a83eb82d8277786fb
4
+ data.tar.gz: 9d18548301ad46bd474671a770c5e528ee7a4f3c
5
5
  SHA512:
6
- metadata.gz: 133c28324c1637b9117e06e33e4585df7b3c072dba7432784550b1c309b24b1635abd18f97a06ce43b9c9650176a7df7bccb0a4d7ddb4cc80d61ac7ddbd067a1
7
- data.tar.gz: 238698df89fbb172922f2224652eddff2fc26d89c593fb90f787bab4293def4d32bcdfd929200c7ef1770b6c33a486feb7435763bae9eb8708e83992c927cd2f
6
+ metadata.gz: b609366f8b1e964dbffbc0a65593bca55d050ac46cac23896627fd0b2b49f9a2b4fc368022e20d3e2866d458322d083a13f1bc44d7cc36c4bff323d7082497ed
7
+ data.tar.gz: 6c6e93549bf4b7eebc659155dcb21ce5d999ef811ea1f8dbceb7c6104b35c3765d0ea6ef16fb706303f9dcd86c99811862fd939af471cbb1a5ff730c9c07aa50
data/.rubocop_todo.yml CHANGED
@@ -28,7 +28,7 @@ Metrics/AbcSize:
28
28
  # Offense count: 3
29
29
  # Configuration parameters: CountComments.
30
30
  Metrics/ClassLength:
31
- Max: 226
31
+ Max: 240
32
32
 
33
33
  # Offense count: 10
34
34
  Metrics/CyclomaticComplexity:
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
- # inherits from https://github.com/ruby-grape/danger
1
+ danger.import_dangerfile(gem: 'ruby-grape-danger')
data/Gemfile CHANGED
@@ -16,4 +16,8 @@ if RUBY_VERSION < '2.2.2'
16
16
  gem 'activesupport', '<5.0.0'
17
17
  end
18
18
 
19
- gem 'danger', '~> 2.1', require: false
19
+ group :test do
20
+ gem 'ruby-grape-danger', '~> 0.1.0', require: false
21
+ gem 'grape-entity'
22
+ gem 'grape-swagger-entity'
23
+ end
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.21.1 (next) | 2.0 | >= 0.12.0 ... <= 0.16.2 | <= 0.5.1 | >= 2.4.1 |
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
- ### Markdown in Detail
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
- # Example
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
- ## Grouping the API list using Namespace
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
- # Example
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
- @target_class.combined_namespaces[endpoint.namespace.sub(/^\//, '')] = ns if ns
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
- api_doc = options[:api_documentation].dup
35
- specific_api_doc = options[:specific_api_documentation].dup
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, options[:format])
41
- end if options[:format]
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
- output = swagger_object(
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
- target_routes = target_class.combined_namespace_routes
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
- # getting of a specific/named route of the swagger2.0 spec file
63
- desc specific_api_doc.delete(:desc), { params:
64
- specific_api_doc.delete(:params) || {} }.merge(specific_api_doc)
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
- output = swagger_object(
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
- request_params = parse_request_params(required)
223
- end
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
- return route.params if route.params.present? && !route.settings[:declared_params].present?
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?(:name) ? name.name.demodulize.camelize : name.split('::').last
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
- route_hidden = route_hidden.call if route_hidden.is_a?(Proc)
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
@@ -1,3 +1,3 @@
1
1
  module GrapeSwagger
2
- VERSION = '0.23.0'.freeze
2
+ VERSION = '0.24.0'.freeze
3
3
  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
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'host in the swagger_doc' do
4
- include_context 'the api entities'
5
-
6
4
  before :all do
7
5
  module TheApi
8
6
  class EmptyApi < Grape::API
@@ -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.23.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-08-05 00:00:00.000000000 Z
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.4
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