grape 1.3.3 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +111 -2
  3. data/CONTRIBUTING.md +2 -1
  4. data/README.md +135 -23
  5. data/UPGRADING.md +237 -46
  6. data/grape.gemspec +5 -5
  7. data/lib/grape/api/instance.rb +34 -42
  8. data/lib/grape/api.rb +21 -16
  9. data/lib/grape/cookies.rb +2 -0
  10. data/lib/grape/dsl/callbacks.rb +1 -1
  11. data/lib/grape/dsl/desc.rb +3 -5
  12. data/lib/grape/dsl/headers.rb +5 -2
  13. data/lib/grape/dsl/helpers.rb +8 -5
  14. data/lib/grape/dsl/inside_route.rb +72 -53
  15. data/lib/grape/dsl/middleware.rb +4 -4
  16. data/lib/grape/dsl/parameters.rb +11 -7
  17. data/lib/grape/dsl/request_response.rb +9 -6
  18. data/lib/grape/dsl/routing.rb +8 -9
  19. data/lib/grape/dsl/settings.rb +5 -5
  20. data/lib/grape/dsl/validations.rb +18 -1
  21. data/lib/grape/eager_load.rb +1 -1
  22. data/lib/grape/endpoint.rb +29 -42
  23. data/lib/grape/error_formatter/json.rb +2 -6
  24. data/lib/grape/error_formatter/xml.rb +2 -6
  25. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  26. data/lib/grape/exceptions/validation.rb +2 -3
  27. data/lib/grape/exceptions/validation_errors.rb +1 -1
  28. data/lib/grape/formatter/json.rb +1 -0
  29. data/lib/grape/formatter/serializable_hash.rb +2 -1
  30. data/lib/grape/formatter/xml.rb +1 -0
  31. data/lib/grape/locale/en.yml +1 -1
  32. data/lib/grape/middleware/auth/base.rb +3 -3
  33. data/lib/grape/middleware/auth/dsl.rb +7 -1
  34. data/lib/grape/middleware/base.rb +6 -3
  35. data/lib/grape/middleware/error.rb +11 -13
  36. data/lib/grape/middleware/formatter.rb +7 -7
  37. data/lib/grape/middleware/stack.rb +10 -3
  38. data/lib/grape/middleware/versioner/accept_version_header.rb +3 -5
  39. data/lib/grape/middleware/versioner/header.rb +6 -4
  40. data/lib/grape/middleware/versioner/param.rb +1 -0
  41. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +2 -1
  42. data/lib/grape/middleware/versioner/path.rb +2 -0
  43. data/lib/grape/parser/json.rb +1 -1
  44. data/lib/grape/parser/xml.rb +1 -1
  45. data/lib/grape/path.rb +1 -0
  46. data/lib/grape/request.rb +4 -1
  47. data/lib/grape/router/attribute_translator.rb +3 -3
  48. data/lib/grape/router/pattern.rb +1 -1
  49. data/lib/grape/router/route.rb +2 -2
  50. data/lib/grape/router.rb +31 -30
  51. data/lib/grape/{serve_file → serve_stream}/file_body.rb +1 -1
  52. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +1 -1
  53. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +8 -8
  54. data/lib/grape/util/base_inheritable.rb +2 -2
  55. data/lib/grape/util/inheritable_setting.rb +1 -3
  56. data/lib/grape/util/lazy_value.rb +4 -2
  57. data/lib/grape/util/strict_hash_configuration.rb +1 -1
  58. data/lib/grape/validations/attributes_iterator.rb +8 -0
  59. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  60. data/lib/grape/validations/params_scope.rb +97 -62
  61. data/lib/grape/validations/single_attribute_iterator.rb +1 -1
  62. data/lib/grape/validations/types/custom_type_coercer.rb +16 -3
  63. data/lib/grape/validations/types/dry_type_coercer.rb +1 -1
  64. data/lib/grape/validations/types/invalid_value.rb +24 -0
  65. data/lib/grape/validations/types/json.rb +2 -1
  66. data/lib/grape/validations/types/primitive_coercer.rb +4 -5
  67. data/lib/grape/validations/types.rb +1 -4
  68. data/lib/grape/validations/validator_factory.rb +1 -1
  69. data/lib/grape/validations/validators/all_or_none.rb +8 -5
  70. data/lib/grape/validations/validators/allow_blank.rb +9 -7
  71. data/lib/grape/validations/validators/as.rb +6 -8
  72. data/lib/grape/validations/validators/at_least_one_of.rb +7 -4
  73. data/lib/grape/validations/validators/base.rb +74 -69
  74. data/lib/grape/validations/validators/coerce.rb +63 -76
  75. data/lib/grape/validations/validators/default.rb +36 -34
  76. data/lib/grape/validations/validators/exactly_one_of.rb +9 -6
  77. data/lib/grape/validations/validators/except_values.rb +13 -11
  78. data/lib/grape/validations/validators/multiple_params_base.rb +24 -19
  79. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -5
  80. data/lib/grape/validations/validators/presence.rb +7 -4
  81. data/lib/grape/validations/validators/regexp.rb +8 -5
  82. data/lib/grape/validations/validators/same_as.rb +18 -15
  83. data/lib/grape/validations/validators/values.rb +61 -56
  84. data/lib/grape/validations.rb +6 -0
  85. data/lib/grape/version.rb +1 -1
  86. data/lib/grape.rb +7 -3
  87. data/spec/grape/api/custom_validations_spec.rb +77 -45
  88. data/spec/grape/api/deeply_included_options_spec.rb +3 -3
  89. data/spec/grape/api/defines_boolean_in_params_spec.rb +2 -1
  90. data/spec/grape/api/invalid_format_spec.rb +2 -0
  91. data/spec/grape/api/recognize_path_spec.rb +1 -1
  92. data/spec/grape/api/routes_with_requirements_spec.rb +8 -8
  93. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +9 -15
  94. data/spec/grape/api_remount_spec.rb +25 -19
  95. data/spec/grape/api_spec.rb +576 -211
  96. data/spec/grape/dsl/callbacks_spec.rb +2 -1
  97. data/spec/grape/dsl/headers_spec.rb +39 -9
  98. data/spec/grape/dsl/helpers_spec.rb +3 -2
  99. data/spec/grape/dsl/inside_route_spec.rb +185 -34
  100. data/spec/grape/dsl/logger_spec.rb +16 -18
  101. data/spec/grape/dsl/middleware_spec.rb +2 -1
  102. data/spec/grape/dsl/parameters_spec.rb +2 -0
  103. data/spec/grape/dsl/request_response_spec.rb +1 -0
  104. data/spec/grape/dsl/routing_spec.rb +10 -7
  105. data/spec/grape/endpoint/declared_spec.rb +848 -0
  106. data/spec/grape/endpoint_spec.rb +77 -589
  107. data/spec/grape/entity_spec.rb +29 -23
  108. data/spec/grape/exceptions/body_parse_errors_spec.rb +3 -0
  109. data/spec/grape/exceptions/invalid_accept_header_spec.rb +61 -22
  110. data/spec/grape/exceptions/validation_errors_spec.rb +13 -10
  111. data/spec/grape/exceptions/validation_spec.rb +5 -3
  112. data/spec/grape/extensions/param_builders/hash_spec.rb +7 -7
  113. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +8 -8
  114. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +8 -8
  115. data/spec/grape/integration/rack_sendfile_spec.rb +13 -9
  116. data/spec/grape/loading_spec.rb +8 -8
  117. data/spec/grape/middleware/auth/dsl_spec.rb +15 -6
  118. data/spec/grape/middleware/auth/strategies_spec.rb +61 -21
  119. data/spec/grape/middleware/base_spec.rb +24 -15
  120. data/spec/grape/middleware/error_spec.rb +3 -3
  121. data/spec/grape/middleware/exception_spec.rb +111 -161
  122. data/spec/grape/middleware/formatter_spec.rb +28 -7
  123. data/spec/grape/middleware/globals_spec.rb +7 -4
  124. data/spec/grape/middleware/stack_spec.rb +15 -12
  125. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +2 -1
  126. data/spec/grape/middleware/versioner/header_spec.rb +14 -13
  127. data/spec/grape/middleware/versioner/param_spec.rb +7 -1
  128. data/spec/grape/middleware/versioner/path_spec.rb +5 -1
  129. data/spec/grape/middleware/versioner_spec.rb +1 -1
  130. data/spec/grape/parser_spec.rb +4 -0
  131. data/spec/grape/path_spec.rb +52 -52
  132. data/spec/grape/presenters/presenter_spec.rb +7 -6
  133. data/spec/grape/request_spec.rb +6 -4
  134. data/spec/grape/util/inheritable_setting_spec.rb +7 -7
  135. data/spec/grape/util/inheritable_values_spec.rb +3 -2
  136. data/spec/grape/util/reverse_stackable_values_spec.rb +3 -1
  137. data/spec/grape/util/stackable_values_spec.rb +7 -5
  138. data/spec/grape/validations/instance_behaivour_spec.rb +9 -10
  139. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +14 -3
  140. data/spec/grape/validations/params_scope_spec.rb +72 -10
  141. data/spec/grape/validations/single_attribute_iterator_spec.rb +18 -6
  142. data/spec/grape/validations/types/primitive_coercer_spec.rb +63 -7
  143. data/spec/grape/validations/types_spec.rb +8 -8
  144. data/spec/grape/validations/validators/all_or_none_spec.rb +50 -56
  145. data/spec/grape/validations/validators/allow_blank_spec.rb +136 -140
  146. data/spec/grape/validations/validators/at_least_one_of_spec.rb +50 -56
  147. data/spec/grape/validations/validators/coerce_spec.rb +248 -33
  148. data/spec/grape/validations/validators/default_spec.rb +121 -78
  149. data/spec/grape/validations/validators/exactly_one_of_spec.rb +71 -77
  150. data/spec/grape/validations/validators/except_values_spec.rb +4 -3
  151. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +71 -77
  152. data/spec/grape/validations/validators/presence_spec.rb +16 -1
  153. data/spec/grape/validations/validators/regexp_spec.rb +25 -31
  154. data/spec/grape/validations/validators/same_as_spec.rb +14 -20
  155. data/spec/grape/validations/validators/values_spec.rb +183 -178
  156. data/spec/grape/validations_spec.rb +342 -29
  157. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  158. data/spec/integration/multi_json/json_spec.rb +1 -1
  159. data/spec/integration/multi_xml/xml_spec.rb +1 -1
  160. data/spec/shared/versioning_examples.rb +32 -29
  161. data/spec/spec_helper.rb +12 -12
  162. data/spec/support/basic_auth_encode_helpers.rb +1 -1
  163. data/spec/support/chunks.rb +14 -0
  164. data/spec/support/versioned_helpers.rb +4 -6
  165. metadata +110 -102
@@ -31,11 +31,13 @@ describe Grape::Endpoint do
31
31
  expect(last_response.status).to eq 200
32
32
  expect(last_response.body).to eq(::Grape::Json.dump(id: 'foo', format: nil))
33
33
  end
34
+
34
35
  it 'json format' do
35
36
  get '/foo.json'
36
37
  expect(last_response.status).to eq 200
37
38
  expect(last_response.body).to eq(::Grape::Json.dump(id: 'foo', format: 'json'))
38
39
  end
40
+
39
41
  it 'invalid format' do
40
42
  get '/foo.invalid'
41
43
  expect(last_response.status).to eq 200
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
 
5
5
  describe Grape::API do
6
6
  describe '.recognize_path' do
7
- subject { Class.new(Grape::API) }
7
+ subject { Class.new(described_class) }
8
8
 
9
9
  it 'fetches endpoint by given path' do
10
10
  subject.get('/foo/:id') {}
@@ -11,7 +11,7 @@ describe Grape::Endpoint do
11
11
 
12
12
  context 'get' do
13
13
  it 'routes to a namespace param with dots' do
14
- subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^\/]+} } do
14
+ subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
15
15
  get '/' do
16
16
  params[:ns_with_dots]
17
17
  end
@@ -23,8 +23,8 @@ describe Grape::Endpoint do
23
23
  end
24
24
 
25
25
  it 'routes to a path with multiple params with dots' do
26
- subject.get ':id_with_dots/:another_id_with_dots', requirements: { id_with_dots: %r{[^\/]+},
27
- another_id_with_dots: %r{[^\/]+} } do
26
+ subject.get ':id_with_dots/:another_id_with_dots', requirements: { id_with_dots: %r{[^/]+},
27
+ another_id_with_dots: %r{[^/]+} } do
28
28
  "#{params[:id_with_dots]}/#{params[:another_id_with_dots]}"
29
29
  end
30
30
 
@@ -34,9 +34,9 @@ describe Grape::Endpoint do
34
34
  end
35
35
 
36
36
  it 'routes to namespace and path params with dots, with overridden requirements' do
37
- subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^\/]+} } do
38
- get ':another_id_with_dots', requirements: { ns_with_dots: %r{[^\/]+},
39
- another_id_with_dots: %r{[^\/]+} } do
37
+ subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
38
+ get ':another_id_with_dots', requirements: { ns_with_dots: %r{[^/]+},
39
+ another_id_with_dots: %r{[^/]+} } do
40
40
  "#{params[:ns_with_dots]}/#{params[:another_id_with_dots]}"
41
41
  end
42
42
  end
@@ -47,8 +47,8 @@ describe Grape::Endpoint do
47
47
  end
48
48
 
49
49
  it 'routes to namespace and path params with dots, with merged requirements' do
50
- subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^\/]+} } do
51
- get ':another_id_with_dots', requirements: { another_id_with_dots: %r{[^\/]+} } do
50
+ subject.namespace ':ns_with_dots', requirements: { ns_with_dots: %r{[^/]+} } do
51
+ get ':another_id_with_dots', requirements: { another_id_with_dots: %r{[^/]+} } do
52
52
  "#{params[:ns_with_dots]}/#{params[:another_id_with_dots]}"
53
53
  end
54
54
  end
@@ -3,19 +3,17 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Grape::API::Helpers do
6
- subject do
7
- shared_params = Module.new do
8
- extend Grape::API::Helpers
6
+ let(:app) do
7
+ Class.new(Grape::API) do
8
+ helpers Module.new do
9
+ extend Grape::API::Helpers
9
10
 
10
- params :drink do
11
- optional :beer
12
- optional :wine
13
- exactly_one_of :beer, :wine
11
+ params :drink do
12
+ optional :beer
13
+ optional :wine
14
+ exactly_one_of :beer, :wine
15
+ end
14
16
  end
15
- end
16
-
17
- Class.new(Grape::API) do
18
- helpers shared_params
19
17
  format :json
20
18
 
21
19
  params do
@@ -35,10 +33,6 @@ describe Grape::API::Helpers do
35
33
  end
36
34
  end
37
35
 
38
- def app
39
- subject
40
- end
41
-
42
36
  it 'defines parameters' do
43
37
  get '/', orderType: 'food', pizza: 'mista'
44
38
  expect(last_response.status).to eq 200
@@ -4,8 +4,9 @@ require 'spec_helper'
4
4
  require 'shared/versioning_examples'
5
5
 
6
6
  describe Grape::API do
7
- subject(:a_remounted_api) { Class.new(Grape::API) }
8
- let(:root_api) { Class.new(Grape::API) }
7
+ subject(:a_remounted_api) { Class.new(described_class) }
8
+
9
+ let(:root_api) { Class.new(described_class) }
9
10
 
10
11
  def app
11
12
  root_api
@@ -68,7 +69,7 @@ describe Grape::API do
68
69
  describe 'with dynamic configuration' do
69
70
  context 'when mounting an endpoint conditional on a configuration' do
70
71
  subject(:a_remounted_api) do
71
- Class.new(Grape::API) do
72
+ Class.new(described_class) do
72
73
  get 'always' do
73
74
  'success'
74
75
  end
@@ -101,7 +102,7 @@ describe Grape::API do
101
102
 
102
103
  context 'when using an expression derived from a configuration' do
103
104
  subject(:a_remounted_api) do
104
- Class.new(Grape::API) do
105
+ Class.new(described_class) do
105
106
  get(mounted { "api_name_#{configuration[:api_name]}" }) do
106
107
  'success'
107
108
  end
@@ -126,7 +127,7 @@ describe Grape::API do
126
127
 
127
128
  context 'when the expression lives in a namespace' do
128
129
  subject(:a_remounted_api) do
129
- Class.new(Grape::API) do
130
+ Class.new(described_class) do
130
131
  namespace :base do
131
132
  get(mounted { "api_name_#{configuration[:api_name]}" }) do
132
133
  'success'
@@ -149,7 +150,7 @@ describe Grape::API do
149
150
 
150
151
  context 'when executing a standard block within a `mounted` block with all dynamic params' do
151
152
  subject(:a_remounted_api) do
152
- Class.new(Grape::API) do
153
+ Class.new(described_class) do
153
154
  mounted do
154
155
  desc configuration[:description] do
155
156
  headers configuration[:headers]
@@ -191,7 +192,7 @@ describe Grape::API do
191
192
 
192
193
  context 'when executing a custom block on mount' do
193
194
  subject(:a_remounted_api) do
194
- Class.new(Grape::API) do
195
+ Class.new(described_class) do
195
196
  get 'always' do
196
197
  'success'
197
198
  end
@@ -215,7 +216,7 @@ describe Grape::API do
215
216
 
216
217
  context 'when the configuration is part of the arguments of a method' do
217
218
  subject(:a_remounted_api) do
218
- Class.new(Grape::API) do
219
+ Class.new(described_class) do
219
220
  get configuration[:endpoint_name] do
220
221
  'success'
221
222
  end
@@ -237,7 +238,7 @@ describe Grape::API do
237
238
 
238
239
  context 'when the configuration is the value in a key-arg pair' do
239
240
  subject(:a_remounted_api) do
240
- Class.new(Grape::API) do
241
+ Class.new(described_class) do
241
242
  version 'v1', using: :param, parameter: configuration[:version_param]
242
243
  get 'endpoint' do
243
244
  'version 1'
@@ -267,7 +268,7 @@ describe Grape::API do
267
268
 
268
269
  context 'on the DescSCope' do
269
270
  subject(:a_remounted_api) do
270
- Class.new(Grape::API) do
271
+ Class.new(described_class) do
271
272
  desc 'The description of this' do
272
273
  tags ['not_configurable_tag', configuration[:a_configurable_tag]]
273
274
  end
@@ -284,7 +285,7 @@ describe Grape::API do
284
285
 
285
286
  context 'on the ParamScope' do
286
287
  subject(:a_remounted_api) do
287
- Class.new(Grape::API) do
288
+ Class.new(described_class) do
288
289
  params do
289
290
  requires configuration[:required_param], type: configuration[:required_type]
290
291
  end
@@ -314,7 +315,7 @@ describe Grape::API do
314
315
 
315
316
  context 'on dynamic checks' do
316
317
  subject(:a_remounted_api) do
317
- Class.new(Grape::API) do
318
+ Class.new(described_class) do
318
319
  params do
319
320
  optional :restricted_values, values: -> { [configuration[:allowed_value], 'always'] }
320
321
  end
@@ -340,25 +341,30 @@ describe Grape::API do
340
341
  context 'when the configuration is read within a namespace' do
341
342
  before do
342
343
  a_remounted_api.namespace 'api' do
344
+ params do
345
+ requires configuration[:required_param]
346
+ end
343
347
  get "/#{configuration[:path]}" do
344
348
  '10 votes'
345
349
  end
346
350
  end
347
- root_api.mount a_remounted_api, with: { path: 'votes' }
348
- root_api.mount a_remounted_api, with: { path: 'scores' }
351
+ root_api.mount a_remounted_api, with: { path: 'votes', required_param: 'param_key' }
352
+ root_api.mount a_remounted_api, with: { path: 'scores', required_param: 'param_key' }
349
353
  end
350
354
 
351
355
  it 'will use the dynamic configuration on all routes' do
352
- get 'api/votes'
356
+ get 'api/votes', param_key: 'a'
353
357
  expect(last_response.body).to eql '10 votes'
354
- get 'api/scores'
358
+ get 'api/scores', param_key: 'a'
355
359
  expect(last_response.body).to eql '10 votes'
360
+ get 'api/votes'
361
+ expect(last_response.status).to eq 400
356
362
  end
357
363
  end
358
364
 
359
365
  context 'a very complex configuration example' do
360
366
  before do
361
- top_level_api = Class.new(Grape::API) do
367
+ top_level_api = Class.new(described_class) do
362
368
  remounted_api = Class.new(Grape::API) do
363
369
  get configuration[:endpoint_name] do
364
370
  configuration[:response]
@@ -426,7 +432,7 @@ describe Grape::API do
426
432
 
427
433
  context 'when the configuration is read in a helper' do
428
434
  subject(:a_remounted_api) do
429
- Class.new(Grape::API) do
435
+ Class.new(described_class) do
430
436
  helpers do
431
437
  def printed_response
432
438
  configuration[:some_value]
@@ -449,7 +455,7 @@ describe Grape::API do
449
455
 
450
456
  context 'when the configuration is read within the response block' do
451
457
  subject(:a_remounted_api) do
452
- Class.new(Grape::API) do
458
+ Class.new(described_class) do
453
459
  get 'location' do
454
460
  configuration[:some_value]
455
461
  end