grape 1.1.0 → 1.5.3

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 (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +278 -44
  3. data/LICENSE +1 -1
  4. data/README.md +514 -69
  5. data/UPGRADING.md +424 -17
  6. data/grape.gemspec +13 -2
  7. data/lib/grape.rb +104 -71
  8. data/lib/grape/api.rb +138 -175
  9. data/lib/grape/api/helpers.rb +2 -0
  10. data/lib/grape/api/instance.rb +283 -0
  11. data/lib/grape/config.rb +34 -0
  12. data/lib/grape/content_types.rb +34 -0
  13. data/lib/grape/cookies.rb +2 -0
  14. data/lib/grape/dsl/api.rb +2 -0
  15. data/lib/grape/dsl/callbacks.rb +22 -0
  16. data/lib/grape/dsl/configuration.rb +2 -0
  17. data/lib/grape/dsl/desc.rb +41 -7
  18. data/lib/grape/dsl/headers.rb +2 -0
  19. data/lib/grape/dsl/helpers.rb +5 -2
  20. data/lib/grape/dsl/inside_route.rb +92 -49
  21. data/lib/grape/dsl/logger.rb +2 -0
  22. data/lib/grape/dsl/middleware.rb +9 -0
  23. data/lib/grape/dsl/parameters.rb +25 -14
  24. data/lib/grape/dsl/request_response.rb +4 -2
  25. data/lib/grape/dsl/routing.rb +17 -10
  26. data/lib/grape/dsl/settings.rb +7 -1
  27. data/lib/grape/dsl/validations.rb +24 -4
  28. data/lib/grape/eager_load.rb +20 -0
  29. data/lib/grape/endpoint.rb +59 -35
  30. data/lib/grape/error_formatter.rb +4 -2
  31. data/lib/grape/error_formatter/base.rb +2 -0
  32. data/lib/grape/error_formatter/json.rb +2 -0
  33. data/lib/grape/error_formatter/txt.rb +2 -0
  34. data/lib/grape/error_formatter/xml.rb +2 -0
  35. data/lib/grape/exceptions/base.rb +20 -14
  36. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  37. data/lib/grape/exceptions/incompatible_option_values.rb +2 -0
  38. data/lib/grape/exceptions/invalid_accept_header.rb +2 -0
  39. data/lib/grape/exceptions/invalid_formatter.rb +2 -0
  40. data/lib/grape/exceptions/invalid_message_body.rb +2 -0
  41. data/lib/grape/exceptions/invalid_response.rb +11 -0
  42. data/lib/grape/exceptions/invalid_version_header.rb +2 -0
  43. data/lib/grape/exceptions/invalid_versioner_option.rb +2 -0
  44. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +2 -0
  45. data/lib/grape/exceptions/method_not_allowed.rb +2 -0
  46. data/lib/grape/exceptions/missing_group_type.rb +2 -0
  47. data/lib/grape/exceptions/missing_mime_type.rb +2 -0
  48. data/lib/grape/exceptions/missing_option.rb +2 -0
  49. data/lib/grape/exceptions/missing_vendor_option.rb +2 -0
  50. data/lib/grape/exceptions/unknown_options.rb +2 -0
  51. data/lib/grape/exceptions/unknown_parameter.rb +2 -0
  52. data/lib/grape/exceptions/unknown_validator.rb +2 -0
  53. data/lib/grape/exceptions/unsupported_group_type.rb +2 -0
  54. data/lib/grape/exceptions/validation.rb +4 -2
  55. data/lib/grape/exceptions/validation_array_errors.rb +2 -0
  56. data/lib/grape/exceptions/validation_errors.rb +16 -13
  57. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +4 -3
  58. data/lib/grape/extensions/deep_mergeable_hash.rb +2 -0
  59. data/lib/grape/extensions/deep_symbolize_hash.rb +2 -0
  60. data/lib/grape/extensions/hash.rb +2 -0
  61. data/lib/grape/extensions/hashie/mash.rb +2 -0
  62. data/lib/grape/formatter.rb +5 -3
  63. data/lib/grape/formatter/json.rb +2 -0
  64. data/lib/grape/formatter/serializable_hash.rb +2 -0
  65. data/lib/grape/formatter/txt.rb +2 -0
  66. data/lib/grape/formatter/xml.rb +2 -0
  67. data/lib/grape/http/headers.rb +50 -18
  68. data/lib/grape/locale/en.yml +3 -1
  69. data/lib/grape/middleware/auth/base.rb +7 -7
  70. data/lib/grape/middleware/auth/dsl.rb +2 -0
  71. data/lib/grape/middleware/auth/strategies.rb +2 -0
  72. data/lib/grape/middleware/auth/strategy_info.rb +2 -0
  73. data/lib/grape/middleware/base.rb +10 -7
  74. data/lib/grape/middleware/error.rb +21 -16
  75. data/lib/grape/middleware/filter.rb +2 -0
  76. data/lib/grape/middleware/formatter.rb +8 -6
  77. data/lib/grape/middleware/globals.rb +2 -0
  78. data/lib/grape/middleware/helpers.rb +12 -0
  79. data/lib/grape/middleware/stack.rb +13 -3
  80. data/lib/grape/middleware/versioner.rb +2 -0
  81. data/lib/grape/middleware/versioner/accept_version_header.rb +2 -0
  82. data/lib/grape/middleware/versioner/header.rb +10 -8
  83. data/lib/grape/middleware/versioner/param.rb +3 -1
  84. data/lib/grape/middleware/versioner/parse_media_type_patch.rb +4 -1
  85. data/lib/grape/middleware/versioner/path.rb +3 -1
  86. data/lib/grape/namespace.rb +14 -2
  87. data/lib/grape/parser.rb +4 -2
  88. data/lib/grape/parser/json.rb +3 -1
  89. data/lib/grape/parser/xml.rb +3 -1
  90. data/lib/grape/path.rb +15 -3
  91. data/lib/grape/presenters/presenter.rb +2 -0
  92. data/lib/grape/request.rb +19 -10
  93. data/lib/grape/router.rb +30 -29
  94. data/lib/grape/router/attribute_translator.rb +41 -8
  95. data/lib/grape/router/pattern.rb +20 -16
  96. data/lib/grape/router/route.rb +14 -28
  97. data/lib/grape/{serve_file → serve_stream}/file_body.rb +3 -1
  98. data/lib/grape/{serve_file → serve_stream}/sendfile_response.rb +3 -1
  99. data/lib/grape/{serve_file/file_response.rb → serve_stream/stream_response.rb} +10 -8
  100. data/lib/grape/util/base_inheritable.rb +43 -0
  101. data/lib/grape/util/cache.rb +20 -0
  102. data/lib/grape/util/endpoint_configuration.rb +8 -0
  103. data/lib/grape/util/env.rb +19 -17
  104. data/lib/grape/util/inheritable_setting.rb +2 -0
  105. data/lib/grape/util/inheritable_values.rb +7 -25
  106. data/lib/grape/util/json.rb +2 -0
  107. data/lib/grape/util/lazy_block.rb +27 -0
  108. data/lib/grape/util/lazy_object.rb +43 -0
  109. data/lib/grape/util/lazy_value.rb +98 -0
  110. data/lib/grape/util/registrable.rb +2 -0
  111. data/lib/grape/util/reverse_stackable_values.rb +10 -35
  112. data/lib/grape/util/stackable_values.rb +21 -34
  113. data/lib/grape/util/strict_hash_configuration.rb +2 -0
  114. data/lib/grape/util/xml.rb +2 -0
  115. data/lib/grape/validations.rb +2 -0
  116. data/lib/grape/validations/attributes_iterator.rb +16 -6
  117. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  118. data/lib/grape/validations/params_scope.rb +51 -30
  119. data/lib/grape/validations/single_attribute_iterator.rb +24 -0
  120. data/lib/grape/validations/types.rb +13 -38
  121. data/lib/grape/validations/types/array_coercer.rb +65 -0
  122. data/lib/grape/validations/types/build_coercer.rb +47 -49
  123. data/lib/grape/validations/types/custom_type_coercer.rb +29 -51
  124. data/lib/grape/validations/types/custom_type_collection_coercer.rb +10 -25
  125. data/lib/grape/validations/types/dry_type_coercer.rb +76 -0
  126. data/lib/grape/validations/types/file.rb +22 -18
  127. data/lib/grape/validations/types/invalid_value.rb +24 -0
  128. data/lib/grape/validations/types/json.rb +46 -39
  129. data/lib/grape/validations/types/multiple_type_coercer.rb +14 -33
  130. data/lib/grape/validations/types/primitive_coercer.rb +67 -0
  131. data/lib/grape/validations/types/set_coercer.rb +40 -0
  132. data/lib/grape/validations/types/variant_collection_coercer.rb +5 -13
  133. data/lib/grape/validations/validator_factory.rb +8 -11
  134. data/lib/grape/validations/validators/all_or_none.rb +8 -13
  135. data/lib/grape/validations/validators/allow_blank.rb +3 -1
  136. data/lib/grape/validations/validators/as.rb +5 -4
  137. data/lib/grape/validations/validators/at_least_one_of.rb +7 -13
  138. data/lib/grape/validations/validators/base.rb +20 -16
  139. data/lib/grape/validations/validators/coerce.rb +46 -29
  140. data/lib/grape/validations/validators/default.rb +6 -6
  141. data/lib/grape/validations/validators/exactly_one_of.rb +10 -23
  142. data/lib/grape/validations/validators/except_values.rb +4 -2
  143. data/lib/grape/validations/validators/multiple_params_base.rb +17 -10
  144. data/lib/grape/validations/validators/mutual_exclusion.rb +8 -18
  145. data/lib/grape/validations/validators/presence.rb +3 -1
  146. data/lib/grape/validations/validators/regexp.rb +4 -2
  147. data/lib/grape/validations/validators/same_as.rb +26 -0
  148. data/lib/grape/validations/validators/values.rb +18 -6
  149. data/lib/grape/version.rb +3 -1
  150. data/spec/grape/api/custom_validations_spec.rb +5 -3
  151. data/spec/grape/api/deeply_included_options_spec.rb +2 -0
  152. data/spec/grape/api/defines_boolean_in_params_spec.rb +39 -0
  153. data/spec/grape/api/inherited_helpers_spec.rb +2 -0
  154. data/spec/grape/api/instance_spec.rb +104 -0
  155. data/spec/grape/api/invalid_format_spec.rb +2 -0
  156. data/spec/grape/api/namespace_parameters_in_route_spec.rb +2 -0
  157. data/spec/grape/api/nested_helpers_spec.rb +2 -0
  158. data/spec/grape/api/optional_parameters_in_route_spec.rb +2 -0
  159. data/spec/grape/api/parameters_modification_spec.rb +3 -1
  160. data/spec/grape/api/patch_method_helpers_spec.rb +2 -0
  161. data/spec/grape/api/recognize_path_spec.rb +2 -0
  162. data/spec/grape/api/required_parameters_in_route_spec.rb +2 -0
  163. data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +2 -0
  164. data/spec/grape/api/routes_with_requirements_spec.rb +61 -0
  165. data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +2 -0
  166. data/spec/grape/api/shared_helpers_spec.rb +2 -0
  167. data/spec/grape/api_remount_spec.rb +473 -0
  168. data/spec/grape/api_spec.rb +565 -12
  169. data/spec/grape/config_spec.rb +19 -0
  170. data/spec/grape/dsl/callbacks_spec.rb +2 -0
  171. data/spec/grape/dsl/configuration_spec.rb +2 -0
  172. data/spec/grape/dsl/desc_spec.rb +42 -16
  173. data/spec/grape/dsl/headers_spec.rb +2 -0
  174. data/spec/grape/dsl/helpers_spec.rb +4 -2
  175. data/spec/grape/dsl/inside_route_spec.rb +184 -33
  176. data/spec/grape/dsl/logger_spec.rb +2 -0
  177. data/spec/grape/dsl/middleware_spec.rb +10 -0
  178. data/spec/grape/dsl/parameters_spec.rb +2 -0
  179. data/spec/grape/dsl/request_response_spec.rb +2 -0
  180. data/spec/grape/dsl/routing_spec.rb +12 -0
  181. data/spec/grape/dsl/settings_spec.rb +2 -0
  182. data/spec/grape/dsl/validations_spec.rb +2 -0
  183. data/spec/grape/endpoint/declared_spec.rb +601 -0
  184. data/spec/grape/endpoint_spec.rb +53 -523
  185. data/spec/grape/entity_spec.rb +9 -1
  186. data/spec/grape/exceptions/base_spec.rb +67 -0
  187. data/spec/grape/exceptions/body_parse_errors_spec.rb +2 -0
  188. data/spec/grape/exceptions/invalid_accept_header_spec.rb +2 -0
  189. data/spec/grape/exceptions/invalid_formatter_spec.rb +2 -0
  190. data/spec/grape/exceptions/invalid_response_spec.rb +13 -0
  191. data/spec/grape/exceptions/invalid_versioner_option_spec.rb +2 -0
  192. data/spec/grape/exceptions/missing_mime_type_spec.rb +2 -0
  193. data/spec/grape/exceptions/missing_option_spec.rb +2 -0
  194. data/spec/grape/exceptions/unknown_options_spec.rb +2 -0
  195. data/spec/grape/exceptions/unknown_validator_spec.rb +2 -0
  196. data/spec/grape/exceptions/validation_errors_spec.rb +8 -4
  197. data/spec/grape/exceptions/validation_spec.rb +3 -1
  198. data/spec/grape/extensions/param_builders/hash_spec.rb +2 -0
  199. data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +2 -0
  200. data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +2 -0
  201. data/spec/grape/integration/global_namespace_function_spec.rb +2 -0
  202. data/spec/grape/integration/rack_sendfile_spec.rb +14 -8
  203. data/spec/grape/integration/rack_spec.rb +25 -7
  204. data/spec/grape/loading_spec.rb +2 -0
  205. data/spec/grape/middleware/auth/base_spec.rb +2 -0
  206. data/spec/grape/middleware/auth/dsl_spec.rb +5 -3
  207. data/spec/grape/middleware/auth/strategies_spec.rb +3 -1
  208. data/spec/grape/middleware/base_spec.rb +10 -0
  209. data/spec/grape/middleware/error_spec.rb +3 -1
  210. data/spec/grape/middleware/exception_spec.rb +4 -2
  211. data/spec/grape/middleware/formatter_spec.rb +33 -16
  212. data/spec/grape/middleware/globals_spec.rb +2 -0
  213. data/spec/grape/middleware/stack_spec.rb +12 -0
  214. data/spec/grape/middleware/versioner/accept_version_header_spec.rb +3 -1
  215. data/spec/grape/middleware/versioner/header_spec.rb +9 -1
  216. data/spec/grape/middleware/versioner/param_spec.rb +3 -1
  217. data/spec/grape/middleware/versioner/path_spec.rb +3 -1
  218. data/spec/grape/middleware/versioner_spec.rb +2 -0
  219. data/spec/grape/named_api_spec.rb +21 -0
  220. data/spec/grape/parser_spec.rb +7 -5
  221. data/spec/grape/path_spec.rb +6 -4
  222. data/spec/grape/presenters/presenter_spec.rb +2 -0
  223. data/spec/grape/request_spec.rb +26 -0
  224. data/spec/grape/util/inheritable_setting_spec.rb +2 -0
  225. data/spec/grape/util/inheritable_values_spec.rb +2 -0
  226. data/spec/grape/util/reverse_stackable_values_spec.rb +2 -0
  227. data/spec/grape/util/stackable_values_spec.rb +3 -1
  228. data/spec/grape/util/strict_hash_configuration_spec.rb +2 -0
  229. data/spec/grape/validations/attributes_iterator_spec.rb +2 -0
  230. data/spec/grape/validations/instance_behaivour_spec.rb +5 -3
  231. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +41 -0
  232. data/spec/grape/validations/params_scope_spec.rb +213 -9
  233. data/spec/grape/validations/single_attribute_iterator_spec.rb +58 -0
  234. data/spec/grape/validations/types/array_coercer_spec.rb +35 -0
  235. data/spec/grape/validations/types/primitive_coercer_spec.rb +135 -0
  236. data/spec/grape/validations/types/set_coercer_spec.rb +34 -0
  237. data/spec/grape/validations/types_spec.rb +9 -36
  238. data/spec/grape/validations/validators/all_or_none_spec.rb +140 -30
  239. data/spec/grape/validations/validators/allow_blank_spec.rb +2 -0
  240. data/spec/grape/validations/validators/at_least_one_of_spec.rb +175 -29
  241. data/spec/grape/validations/validators/coerce_spec.rb +476 -135
  242. data/spec/grape/validations/validators/default_spec.rb +172 -0
  243. data/spec/grape/validations/validators/exactly_one_of_spec.rb +204 -38
  244. data/spec/grape/validations/validators/except_values_spec.rb +4 -1
  245. data/spec/grape/validations/validators/mutual_exclusion_spec.rb +186 -27
  246. data/spec/grape/validations/validators/presence_spec.rb +30 -0
  247. data/spec/grape/validations/validators/regexp_spec.rb +2 -0
  248. data/spec/grape/validations/validators/same_as_spec.rb +65 -0
  249. data/spec/grape/validations/validators/values_spec.rb +30 -5
  250. data/spec/grape/validations_spec.rb +388 -50
  251. data/spec/integration/eager_load/eager_load_spec.rb +15 -0
  252. data/spec/integration/multi_json/json_spec.rb +2 -0
  253. data/spec/integration/multi_xml/xml_spec.rb +2 -0
  254. data/spec/shared/versioning_examples.rb +22 -20
  255. data/spec/spec_helper.rb +12 -1
  256. data/spec/support/basic_auth_encode_helpers.rb +2 -0
  257. data/spec/support/chunks.rb +14 -0
  258. data/spec/support/content_type_helpers.rb +2 -0
  259. data/spec/support/eager_load.rb +19 -0
  260. data/spec/support/endpoint_faker.rb +2 -0
  261. data/spec/support/file_streamer.rb +2 -0
  262. data/spec/support/integer_helpers.rb +2 -0
  263. data/spec/support/versioned_helpers.rb +8 -8
  264. metadata +86 -48
  265. data/Appraisals +0 -32
  266. data/Dangerfile +0 -2
  267. data/Gemfile +0 -33
  268. data/Gemfile.lock +0 -231
  269. data/Guardfile +0 -10
  270. data/RELEASING.md +0 -111
  271. data/Rakefile +0 -25
  272. data/benchmark/simple.rb +0 -27
  273. data/benchmark/simple_with_type_coercer.rb +0 -22
  274. data/gemfiles/multi_json.gemfile +0 -35
  275. data/gemfiles/multi_xml.gemfile +0 -35
  276. data/gemfiles/rack_1.5.2.gemfile +0 -35
  277. data/gemfiles/rack_edge.gemfile +0 -35
  278. data/gemfiles/rails_3.gemfile +0 -36
  279. data/gemfiles/rails_4.gemfile +0 -35
  280. data/gemfiles/rails_5.gemfile +0 -35
  281. data/gemfiles/rails_edge.gemfile +0 -35
  282. data/lib/grape/extensions/deep_hash_with_indifferent_access.rb +0 -18
  283. data/lib/grape/util/content_types.rb +0 -26
  284. data/lib/grape/validations/types/virtus_collection_patch.rb +0 -16
  285. data/pkg/grape-0.17.0.gem +0 -0
  286. data/pkg/grape-0.19.0.gem +0 -0
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  class API
3
5
  module Helpers
@@ -0,0 +1,283 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grape/router'
4
+
5
+ module Grape
6
+ class API
7
+ # The API Instance class, is the engine behind Grape::API. Each class that inherits
8
+ # from this will represent a different API instance
9
+ class Instance
10
+ include Grape::DSL::API
11
+
12
+ class << self
13
+ attr_reader :instance
14
+ attr_reader :base
15
+ attr_accessor :configuration
16
+
17
+ def given(conditional_option, &block)
18
+ evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block_given?
19
+ end
20
+
21
+ def mounted(&block)
22
+ evaluate_as_instance_with_configuration(block, lazy: true)
23
+ end
24
+
25
+ def base=(grape_api)
26
+ @base = grape_api
27
+ grape_api.instances << self
28
+ end
29
+
30
+ def to_s
31
+ (base && base.to_s) || super
32
+ end
33
+
34
+ def base_instance?
35
+ self == base.base_instance
36
+ end
37
+
38
+ # A class-level lock to ensure the API is not compiled by multiple
39
+ # threads simultaneously within the same process.
40
+ LOCK = Mutex.new
41
+
42
+ # Clears all defined routes, endpoints, etc., on this API.
43
+ def reset!
44
+ reset_endpoints!
45
+ reset_routes!
46
+ reset_validations!
47
+ end
48
+
49
+ # Parses the API's definition and compiles it into an instance of
50
+ # Grape::API.
51
+ def compile
52
+ @instance ||= new
53
+ end
54
+
55
+ # Wipe the compiled API so we can recompile after changes were made.
56
+ def change!
57
+ @instance = nil
58
+ end
59
+
60
+ # This is the interface point between Rack and Grape; it accepts a request
61
+ # from Rack and ultimately returns an array of three values: the status,
62
+ # the headers, and the body. See [the rack specification]
63
+ # (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
64
+ def call(env)
65
+ compile!
66
+ call!(env)
67
+ end
68
+
69
+ # A non-synchronized version of ::call.
70
+ def call!(env)
71
+ instance.call(env)
72
+ end
73
+
74
+ # (see #cascade?)
75
+ def cascade(value = nil)
76
+ if value.nil?
77
+ inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
78
+ else
79
+ namespace_inheritable(:cascade, value)
80
+ end
81
+ end
82
+
83
+ def compile!
84
+ return if instance
85
+ LOCK.synchronize { compile unless instance }
86
+ end
87
+
88
+ # see Grape::Router#recognize_path
89
+ def recognize_path(path)
90
+ compile!
91
+ instance.router.recognize_path(path)
92
+ end
93
+
94
+ protected
95
+
96
+ def prepare_routes
97
+ endpoints.map(&:routes).flatten
98
+ end
99
+
100
+ # Execute first the provided block, then each of the
101
+ # block passed in. Allows for simple 'before' setups
102
+ # of settings stack pushes.
103
+ def nest(*blocks, &block)
104
+ blocks.reject!(&:nil?)
105
+ if blocks.any?
106
+ evaluate_as_instance_with_configuration(block) if block_given?
107
+ blocks.each { |b| evaluate_as_instance_with_configuration(b) }
108
+ reset_validations!
109
+ else
110
+ instance_eval(&block)
111
+ end
112
+ end
113
+
114
+ def evaluate_as_instance_with_configuration(block, lazy: false)
115
+ lazy_block = Grape::Util::LazyBlock.new do |configuration|
116
+ value_for_configuration = configuration
117
+ if value_for_configuration.respond_to?(:lazy?) && value_for_configuration.lazy?
118
+ self.configuration = value_for_configuration.evaluate
119
+ end
120
+ response = instance_eval(&block)
121
+ self.configuration = value_for_configuration
122
+ response
123
+ end
124
+ if base && base_instance? && lazy
125
+ lazy_block
126
+ else
127
+ lazy_block.evaluate_from(configuration)
128
+ end
129
+ end
130
+
131
+ def inherited(subclass)
132
+ subclass.reset!
133
+ subclass.logger = logger.clone
134
+ end
135
+
136
+ def inherit_settings(other_settings)
137
+ top_level_setting.inherit_from other_settings.point_in_time_copy
138
+
139
+ # Propagate any inherited params down to our endpoints, and reset any
140
+ # compiled routes.
141
+ endpoints.each do |e|
142
+ e.inherit_settings(top_level_setting.namespace_stackable)
143
+ e.reset_routes!
144
+ end
145
+
146
+ reset_routes!
147
+ end
148
+ end
149
+
150
+ attr_reader :router
151
+
152
+ # Builds the routes from the defined endpoints, effectively compiling
153
+ # this API into a usable form.
154
+ def initialize
155
+ @router = Router.new
156
+ add_head_not_allowed_methods_and_options_methods
157
+ self.class.endpoints.each do |endpoint|
158
+ endpoint.mount_in(@router)
159
+ end
160
+
161
+ @router.compile!
162
+ @router.freeze
163
+ end
164
+
165
+ # Handle a request. See Rack documentation for what `env` is.
166
+ def call(env)
167
+ result = @router.call(env)
168
+ result[1].delete(Grape::Http::Headers::X_CASCADE) unless cascade?
169
+ result
170
+ end
171
+
172
+ # Some requests may return a HTTP 404 error if grape cannot find a matching
173
+ # route. In this case, Grape::Router adds a X-Cascade header to the response
174
+ # and sets it to 'pass', indicating to grape's parents they should keep
175
+ # looking for a matching route on other resources.
176
+ #
177
+ # In some applications (e.g. mounting grape on rails), one might need to trap
178
+ # errors from reaching upstream. This is effectivelly done by unsetting
179
+ # X-Cascade. Default :cascade is true.
180
+ def cascade?
181
+ return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade)
182
+ return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options) && self.class.namespace_inheritable(:version_options).key?(:cascade)
183
+ true
184
+ end
185
+
186
+ reset!
187
+
188
+ private
189
+
190
+ # For every resource add a 'OPTIONS' route that returns an HTTP 204 response
191
+ # with a list of HTTP methods that can be called. Also add a route that
192
+ # will return an HTTP 405 response for any HTTP method that the resource
193
+ # cannot handle.
194
+ def add_head_not_allowed_methods_and_options_methods
195
+ versioned_route_configs = collect_route_config_per_pattern
196
+ # The paths we collected are prepared (cf. Path#prepare), so they
197
+ # contain already versioning information when using path versioning.
198
+ # Disable versioning so adding a route won't prepend versioning
199
+ # informations again.
200
+ without_root_prefix do
201
+ without_versioning do
202
+ versioned_route_configs.each do |config|
203
+ allowed_methods = config[:methods].dup
204
+
205
+ unless self.class.namespace_inheritable(:do_not_route_head)
206
+ allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET)
207
+ end
208
+
209
+ allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
210
+
211
+ unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
212
+ config[:endpoint].options[:options_route_enabled] = true
213
+ end
214
+
215
+ attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
216
+ generate_not_allowed_method(config[:pattern], **attributes)
217
+ end
218
+ end
219
+ end
220
+ end
221
+
222
+ def collect_route_config_per_pattern
223
+ all_routes = self.class.endpoints.map(&:routes).flatten
224
+ routes_by_regexp = all_routes.group_by { |route| route.pattern.to_regexp }
225
+
226
+ # Build the configuration based on the first endpoint and the collection of methods supported.
227
+ routes_by_regexp.values.map do |routes|
228
+ last_route = routes.last # Most of the configuration is taken from the last endpoint
229
+ matching_wildchar = routes.any? { |route| route.request_method == '*' }
230
+ {
231
+ options: {},
232
+ pattern: last_route.pattern,
233
+ requirements: last_route.requirements,
234
+ path: last_route.origin,
235
+ endpoint: last_route.app,
236
+ methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method)
237
+ }
238
+ end
239
+ end
240
+
241
+ # Generate a route that returns an HTTP 405 response for a user defined
242
+ # path on methods not specified
243
+ def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
244
+ supported_methods =
245
+ if self.class.namespace_inheritable(:do_not_route_options)
246
+ Grape::Http::Headers::SUPPORTED_METHODS
247
+ else
248
+ Grape::Http::Headers::SUPPORTED_METHODS_WITHOUT_OPTIONS
249
+ end
250
+ not_allowed_methods = supported_methods - allowed_methods
251
+ return if not_allowed_methods.empty?
252
+ @router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
253
+ end
254
+
255
+ # Allows definition of endpoints that ignore the versioning configuration
256
+ # used by the rest of your API.
257
+ def without_versioning(&_block)
258
+ old_version = self.class.namespace_inheritable(:version)
259
+ old_version_options = self.class.namespace_inheritable(:version_options)
260
+
261
+ self.class.namespace_inheritable_to_nil(:version)
262
+ self.class.namespace_inheritable_to_nil(:version_options)
263
+
264
+ yield
265
+
266
+ self.class.namespace_inheritable(:version, old_version)
267
+ self.class.namespace_inheritable(:version_options, old_version_options)
268
+ end
269
+
270
+ # Allows definition of endpoints that ignore the root prefix used by the
271
+ # rest of your API.
272
+ def without_root_prefix(&_block)
273
+ old_prefix = self.class.namespace_inheritable(:root_prefix)
274
+
275
+ self.class.namespace_inheritable_to_nil(:root_prefix)
276
+
277
+ yield
278
+
279
+ self.class.namespace_inheritable(:root_prefix, old_prefix)
280
+ end
281
+ end
282
+ end
283
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ module Config
5
+ class Configuration
6
+ ATTRIBUTES = %i[
7
+ param_builder
8
+ ].freeze
9
+
10
+ attr_accessor(*ATTRIBUTES)
11
+
12
+ def initialize
13
+ reset
14
+ end
15
+
16
+ def reset
17
+ self.param_builder = Grape::Extensions::ActiveSupport::HashWithIndifferentAccess::ParamBuilder
18
+ end
19
+ end
20
+
21
+ def self.extended(base)
22
+ def base.configure
23
+ block_given? ? yield(config) : config
24
+ end
25
+
26
+ def base.config
27
+ @configuration ||= Grape::Config::Configuration.new
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ Grape.extend Grape::Config
34
+ Grape.config.reset
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'grape/util/registrable'
4
+
5
+ module Grape
6
+ module ContentTypes
7
+ extend Util::Registrable
8
+
9
+ # Content types are listed in order of preference.
10
+ CONTENT_TYPES = {
11
+ xml: 'application/xml',
12
+ serializable_hash: 'application/json',
13
+ json: 'application/json',
14
+ binary: 'application/octet-stream',
15
+ txt: 'text/plain'
16
+ }.freeze
17
+
18
+ class << self
19
+ def content_types_for_settings(settings)
20
+ return if settings.blank?
21
+
22
+ settings.each_with_object({}) { |value, result| result.merge!(value) }
23
+ end
24
+
25
+ def content_types_for(from_settings)
26
+ if from_settings.present?
27
+ from_settings
28
+ else
29
+ Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
data/lib/grape/cookies.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  class Cookies
3
5
  def initialize
data/lib/grape/dsl/api.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -43,6 +45,26 @@ module Grape
43
45
  def after(&block)
44
46
  namespace_stackable(:afters, block)
45
47
  end
48
+
49
+ # Allows you to specify a something that will always be executed after a call
50
+ # API call. Unlike the `after` block, this code will run even on
51
+ # unsuccesful requests.
52
+ # @example
53
+ # class ExampleAPI < Grape::API
54
+ # before do
55
+ # ApiLogger.start
56
+ # end
57
+ # finally do
58
+ # ApiLogger.close
59
+ # end
60
+ # end
61
+ #
62
+ # This will make sure that the ApiLogger is opened and closed around every
63
+ # request
64
+ # @param ensured_block [Proc] The block to be executed after every api_call
65
+ def finally(&block)
66
+ namespace_stackable(:finallies, block)
67
+ end
46
68
  end
47
69
  end
48
70
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support/concern'
2
4
 
3
5
  module Grape
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Grape
2
4
  module DSL
3
5
  module Desc
@@ -9,6 +11,7 @@ module Grape
9
11
  # @param options [Hash] other properties you can set to describe the
10
12
  # endpoint or namespace. Optional.
11
13
  # @option options :detail [String] additional detail about this endpoint
14
+ # @option options :summary [String] summary for this endpoint
12
15
  # @option options :params [Hash] param types and info. normally, you set
13
16
  # these via the `params` dsl method.
14
17
  # @option options :entity [Grape::Entity] the entity returned upon a
@@ -16,7 +19,16 @@ module Grape
16
19
  # @option options :http_codes [Array[Array]] possible HTTP codes this
17
20
  # endpoint may return, with their meanings, in a 2d array
18
21
  # @option options :named [String] a specific name to help find this route
22
+ # @option options :body_name [String] override the autogenerated body name param
19
23
  # @option options :headers [Hash] HTTP headers this method can accept
24
+ # @option options :hidden [Boolean] hide the endpoint or not
25
+ # @option options :deprecated [Boolean] deprecate the endpoint or not
26
+ # @option options :is_array [Boolean] response entity is array or not
27
+ # @option options :nickname [String] nickname of the endpoint
28
+ # @option options :produces [Array[String]] a list of MIME types the endpoint produce
29
+ # @option options :consumes [Array[String]] a list of MIME types the endpoint consume
30
+ # @option options :security [Array[Hash]] a list of security schemes
31
+ # @option options :tags [Array[String]] a list of tags
20
32
  # @yield a block yielding an instance context with methods mapping to
21
33
  # each of the above, except that :entity is also aliased as #success
22
34
  # and :http_codes is aliased as #failure.
@@ -39,7 +51,17 @@ module Grape
39
51
  #
40
52
  def desc(description, options = {}, &config_block)
41
53
  if block_given?
42
- config_class = desc_container
54
+ endpoint_configuration = if defined?(configuration)
55
+ # When the instance is mounted - the configuration is executed on mount time
56
+ if configuration.respond_to?(:evaluate)
57
+ configuration.evaluate
58
+ # Within `given` or `mounted blocks` the configuration is already evaluated
59
+ elsif configuration.is_a?(Hash)
60
+ configuration
61
+ end
62
+ end
63
+ endpoint_configuration ||= {}
64
+ config_class = desc_container(endpoint_configuration)
43
65
 
44
66
  config_class.configure do
45
67
  description description
@@ -59,13 +81,12 @@ module Grape
59
81
  end
60
82
 
61
83
  def description_field(field, value = nil)
84
+ description = route_setting(:description)
62
85
  if value
63
- description = route_setting(:description)
64
86
  description ||= route_setting(:description, {})
65
87
  description[field] = value
66
- else
67
- description = route_setting(:description)
68
- description[field] if description
88
+ elsif description
89
+ description[field]
69
90
  end
70
91
  end
71
92
 
@@ -75,17 +96,30 @@ module Grape
75
96
  end
76
97
 
77
98
  # Returns an object which configures itself via an instance-context DSL.
78
- def desc_container
99
+ def desc_container(endpoint_configuration)
79
100
  Module.new do
80
101
  include Grape::Util::StrictHashConfiguration.module(
102
+ :summary,
81
103
  :description,
82
104
  :detail,
83
105
  :params,
84
106
  :entity,
85
107
  :http_codes,
86
108
  :named,
87
- :headers
109
+ :body_name,
110
+ :headers,
111
+ :hidden,
112
+ :deprecated,
113
+ :is_array,
114
+ :nickname,
115
+ :produces,
116
+ :consumes,
117
+ :security,
118
+ :tags
88
119
  )
120
+ config_context.define_singleton_method(:configuration) do
121
+ endpoint_configuration
122
+ end
89
123
 
90
124
  def config_context.success(*args)
91
125
  entity(*args)