grape 0.1.1 → 2.4.0

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 (197) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1167 -0
  3. data/CONTRIBUTING.md +156 -0
  4. data/LICENSE +1 -1
  5. data/README.md +4192 -0
  6. data/UPGRADING.md +1697 -0
  7. data/grape.gemspec +28 -105
  8. data/grape.png +0 -0
  9. data/lib/grape/api/helpers.rb +9 -0
  10. data/lib/grape/api/instance.rb +247 -0
  11. data/lib/grape/api.rb +158 -194
  12. data/lib/grape/content_types.rb +31 -0
  13. data/lib/grape/cookies.rb +50 -0
  14. data/lib/grape/dry_types.rb +10 -0
  15. data/lib/grape/dsl/api.rb +17 -0
  16. data/lib/grape/dsl/callbacks.rb +69 -0
  17. data/lib/grape/dsl/configuration.rb +15 -0
  18. data/lib/grape/dsl/desc.rb +124 -0
  19. data/lib/grape/dsl/headers.rb +21 -0
  20. data/lib/grape/dsl/helpers.rb +108 -0
  21. data/lib/grape/dsl/inside_route.rb +454 -0
  22. data/lib/grape/dsl/logger.rb +22 -0
  23. data/lib/grape/dsl/middleware.rb +54 -0
  24. data/lib/grape/dsl/parameters.rb +266 -0
  25. data/lib/grape/dsl/request_response.rb +171 -0
  26. data/lib/grape/dsl/routing.rb +248 -0
  27. data/lib/grape/dsl/settings.rb +179 -0
  28. data/lib/grape/dsl/validations.rb +57 -0
  29. data/lib/grape/endpoint.rb +398 -68
  30. data/lib/grape/env.rb +20 -0
  31. data/lib/grape/error_formatter/base.rb +68 -0
  32. data/lib/grape/error_formatter/json.rb +28 -0
  33. data/lib/grape/error_formatter/serializable_hash.rb +7 -0
  34. data/lib/grape/error_formatter/txt.rb +21 -0
  35. data/lib/grape/error_formatter/xml.rb +11 -0
  36. data/lib/grape/error_formatter.rb +15 -0
  37. data/lib/grape/exceptions/base.rb +76 -0
  38. data/lib/grape/exceptions/conflicting_types.rb +11 -0
  39. data/lib/grape/exceptions/empty_message_body.rb +11 -0
  40. data/lib/grape/exceptions/incompatible_option_values.rb +11 -0
  41. data/lib/grape/exceptions/invalid_accept_header.rb +11 -0
  42. data/lib/grape/exceptions/invalid_formatter.rb +11 -0
  43. data/lib/grape/exceptions/invalid_message_body.rb +11 -0
  44. data/lib/grape/exceptions/invalid_parameters.rb +11 -0
  45. data/lib/grape/exceptions/invalid_response.rb +11 -0
  46. data/lib/grape/exceptions/invalid_version_header.rb +11 -0
  47. data/lib/grape/exceptions/invalid_versioner_option.rb +11 -0
  48. data/lib/grape/exceptions/invalid_with_option_for_represent.rb +11 -0
  49. data/lib/grape/exceptions/method_not_allowed.rb +11 -0
  50. data/lib/grape/exceptions/missing_group_type.rb +13 -0
  51. data/lib/grape/exceptions/missing_mime_type.rb +11 -0
  52. data/lib/grape/exceptions/missing_option.rb +11 -0
  53. data/lib/grape/exceptions/missing_vendor_option.rb +11 -0
  54. data/lib/grape/exceptions/too_deep_parameters.rb +11 -0
  55. data/lib/grape/exceptions/too_many_multipart_files.rb +11 -0
  56. data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
  57. data/lib/grape/exceptions/unknown_options.rb +11 -0
  58. data/lib/grape/exceptions/unknown_parameter.rb +11 -0
  59. data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
  60. data/lib/grape/exceptions/unknown_validator.rb +11 -0
  61. data/lib/grape/exceptions/unsupported_group_type.rb +13 -0
  62. data/lib/grape/exceptions/validation.rb +25 -0
  63. data/lib/grape/exceptions/validation_array_errors.rb +14 -0
  64. data/lib/grape/exceptions/validation_errors.rb +53 -0
  65. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +24 -0
  66. data/lib/grape/extensions/hash.rb +27 -0
  67. data/lib/grape/extensions/hashie/mash.rb +24 -0
  68. data/lib/grape/formatter/base.rb +16 -0
  69. data/lib/grape/formatter/json.rb +13 -0
  70. data/lib/grape/formatter/serializable_hash.rb +39 -0
  71. data/lib/grape/formatter/txt.rb +11 -0
  72. data/lib/grape/formatter/xml.rb +13 -0
  73. data/lib/grape/formatter.rb +17 -0
  74. data/lib/grape/json.rb +10 -0
  75. data/lib/grape/locale/en.yml +59 -0
  76. data/lib/grape/middleware/auth/base.rb +23 -0
  77. data/lib/grape/middleware/auth/dsl.rb +39 -0
  78. data/lib/grape/middleware/auth/strategies.rb +25 -0
  79. data/lib/grape/middleware/auth/strategy_info.rb +15 -0
  80. data/lib/grape/middleware/base.rb +89 -18
  81. data/lib/grape/middleware/error.rb +129 -10
  82. data/lib/grape/middleware/filter.rb +19 -0
  83. data/lib/grape/middleware/formatter.rb +124 -82
  84. data/lib/grape/middleware/globals.rb +14 -0
  85. data/lib/grape/middleware/stack.rb +109 -0
  86. data/lib/grape/middleware/versioner/accept_version_header.rb +38 -0
  87. data/lib/grape/middleware/versioner/base.rb +74 -0
  88. data/lib/grape/middleware/versioner/header.rb +127 -0
  89. data/lib/grape/middleware/versioner/param.rb +32 -0
  90. data/lib/grape/middleware/versioner/path.rb +40 -0
  91. data/lib/grape/middleware/versioner.rb +21 -21
  92. data/lib/grape/namespace.rb +46 -0
  93. data/lib/grape/params_builder/base.rb +18 -0
  94. data/lib/grape/params_builder/hash.rb +11 -0
  95. data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
  96. data/lib/grape/params_builder/hashie_mash.rb +11 -0
  97. data/lib/grape/params_builder.rb +32 -0
  98. data/lib/grape/parser/base.rb +16 -0
  99. data/lib/grape/parser/json.rb +14 -0
  100. data/lib/grape/parser/xml.rb +14 -0
  101. data/lib/grape/parser.rb +15 -0
  102. data/lib/grape/path.rb +76 -0
  103. data/lib/grape/presenters/presenter.rb +11 -0
  104. data/lib/grape/railtie.rb +9 -0
  105. data/lib/grape/request.rb +190 -0
  106. data/lib/grape/router/base_route.rb +39 -0
  107. data/lib/grape/router/greedy_route.rb +20 -0
  108. data/lib/grape/router/pattern.rb +81 -0
  109. data/lib/grape/router/route.rb +62 -0
  110. data/lib/grape/router.rb +190 -0
  111. data/lib/grape/serve_stream/file_body.rb +36 -0
  112. data/lib/grape/serve_stream/sendfile_response.rb +21 -0
  113. data/lib/grape/serve_stream/stream_response.rb +23 -0
  114. data/lib/grape/types/invalid_value.rb +8 -0
  115. data/lib/grape/util/base_inheritable.rb +43 -0
  116. data/lib/grape/util/cache.rb +17 -0
  117. data/lib/grape/util/endpoint_configuration.rb +8 -0
  118. data/lib/grape/util/header.rb +13 -0
  119. data/lib/grape/util/inheritable_setting.rb +100 -0
  120. data/lib/grape/util/inheritable_values.rb +29 -0
  121. data/lib/grape/util/lazy/block.rb +29 -0
  122. data/lib/grape/util/lazy/value.rb +38 -0
  123. data/lib/grape/util/lazy/value_array.rb +21 -0
  124. data/lib/grape/util/lazy/value_enumerable.rb +34 -0
  125. data/lib/grape/util/lazy/value_hash.rb +21 -0
  126. data/lib/grape/util/media_type.rb +70 -0
  127. data/lib/grape/util/registry.rb +27 -0
  128. data/lib/grape/util/reverse_stackable_values.rb +15 -0
  129. data/lib/grape/util/stackable_values.rb +36 -0
  130. data/lib/grape/util/strict_hash_configuration.rb +108 -0
  131. data/lib/grape/validations/attributes_doc.rb +60 -0
  132. data/lib/grape/validations/attributes_iterator.rb +62 -0
  133. data/lib/grape/validations/contract_scope.rb +34 -0
  134. data/lib/grape/validations/multiple_attributes_iterator.rb +13 -0
  135. data/lib/grape/validations/params_scope.rb +538 -0
  136. data/lib/grape/validations/single_attribute_iterator.rb +26 -0
  137. data/lib/grape/validations/types/array_coercer.rb +61 -0
  138. data/lib/grape/validations/types/custom_type_coercer.rb +164 -0
  139. data/lib/grape/validations/types/custom_type_collection_coercer.rb +56 -0
  140. data/lib/grape/validations/types/dry_type_coercer.rb +66 -0
  141. data/lib/grape/validations/types/file.rb +31 -0
  142. data/lib/grape/validations/types/invalid_value.rb +17 -0
  143. data/lib/grape/validations/types/json.rb +71 -0
  144. data/lib/grape/validations/types/multiple_type_coercer.rb +57 -0
  145. data/lib/grape/validations/types/primitive_coercer.rb +73 -0
  146. data/lib/grape/validations/types/set_coercer.rb +35 -0
  147. data/lib/grape/validations/types/variant_collection_coercer.rb +51 -0
  148. data/lib/grape/validations/types.rb +213 -0
  149. data/lib/grape/validations/validator_factory.rb +15 -0
  150. data/lib/grape/validations/validators/all_or_none_of_validator.rb +16 -0
  151. data/lib/grape/validations/validators/allow_blank_validator.rb +20 -0
  152. data/lib/grape/validations/validators/as_validator.rb +14 -0
  153. data/lib/grape/validations/validators/at_least_one_of_validator.rb +15 -0
  154. data/lib/grape/validations/validators/base.rb +88 -0
  155. data/lib/grape/validations/validators/coerce_validator.rb +75 -0
  156. data/lib/grape/validations/validators/contract_scope_validator.rb +41 -0
  157. data/lib/grape/validations/validators/default_validator.rb +37 -0
  158. data/lib/grape/validations/validators/exactly_one_of_validator.rb +17 -0
  159. data/lib/grape/validations/validators/except_values_validator.rb +24 -0
  160. data/lib/grape/validations/validators/length_validator.rb +49 -0
  161. data/lib/grape/validations/validators/multiple_params_base.rb +34 -0
  162. data/lib/grape/validations/validators/mutual_exclusion_validator.rb +16 -0
  163. data/lib/grape/validations/validators/presence_validator.rb +15 -0
  164. data/lib/grape/validations/validators/regexp_validator.rb +16 -0
  165. data/lib/grape/validations/validators/same_as_validator.rb +29 -0
  166. data/lib/grape/validations/validators/values_validator.rb +60 -0
  167. data/lib/grape/validations.rb +21 -0
  168. data/lib/grape/version.rb +6 -0
  169. data/lib/grape/xml.rb +10 -0
  170. data/lib/grape.rb +81 -17
  171. metadata +250 -192
  172. data/.document +0 -5
  173. data/.gitignore +0 -23
  174. data/.rspec +0 -2
  175. data/.rvmrc +0 -1
  176. data/Gemfile +0 -21
  177. data/Gemfile.lock +0 -58
  178. data/README.markdown +0 -75
  179. data/Rakefile +0 -70
  180. data/VERSION +0 -1
  181. data/autotest/discover.rb +0 -1
  182. data/lib/grape/middleware/auth/basic.rb +0 -30
  183. data/lib/grape/middleware/auth/oauth2.rb +0 -55
  184. data/lib/grape/middleware/prefixer.rb +0 -21
  185. data/lib/grape/middleware_stack.rb +0 -35
  186. data/spec/grape/api_spec.rb +0 -343
  187. data/spec/grape/endpoint_spec.rb +0 -104
  188. data/spec/grape/middleware/auth/basic_spec.rb +0 -31
  189. data/spec/grape/middleware/auth/oauth2_spec.rb +0 -88
  190. data/spec/grape/middleware/base_spec.rb +0 -63
  191. data/spec/grape/middleware/error_spec.rb +0 -49
  192. data/spec/grape/middleware/formatter_spec.rb +0 -87
  193. data/spec/grape/middleware/prefixer_spec.rb +0 -30
  194. data/spec/grape/middleware/versioner_spec.rb +0 -40
  195. data/spec/grape/middleware_stack_spec.rb +0 -47
  196. data/spec/grape_spec.rb +0 -1
  197. data/spec/spec_helper.rb +0 -20
data/grape.gemspec CHANGED
@@ -1,110 +1,33 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ # frozen_string_literal: true
5
2
 
6
- Gem::Specification.new do |s|
7
- s.name = %q{grape}
8
- s.version = "0.1.1"
3
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
4
+ require 'grape/version'
9
5
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Michael Bleigh"]
12
- s.date = %q{2010-11-14}
13
- s.description = %q{A Ruby framework for rapid API development with great conventions.}
14
- s.email = %q{michael@intridea.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.markdown"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- ".rspec",
23
- ".rvmrc",
24
- "Gemfile",
25
- "Gemfile.lock",
26
- "LICENSE",
27
- "README.markdown",
28
- "Rakefile",
29
- "VERSION",
30
- "autotest/discover.rb",
31
- "grape.gemspec",
32
- "lib/grape.rb",
33
- "lib/grape/api.rb",
34
- "lib/grape/endpoint.rb",
35
- "lib/grape/middleware/auth/basic.rb",
36
- "lib/grape/middleware/auth/oauth2.rb",
37
- "lib/grape/middleware/base.rb",
38
- "lib/grape/middleware/error.rb",
39
- "lib/grape/middleware/formatter.rb",
40
- "lib/grape/middleware/prefixer.rb",
41
- "lib/grape/middleware/versioner.rb",
42
- "lib/grape/middleware_stack.rb",
43
- "spec/grape/api_spec.rb",
44
- "spec/grape/endpoint_spec.rb",
45
- "spec/grape/middleware/auth/basic_spec.rb",
46
- "spec/grape/middleware/auth/oauth2_spec.rb",
47
- "spec/grape/middleware/base_spec.rb",
48
- "spec/grape/middleware/error_spec.rb",
49
- "spec/grape/middleware/formatter_spec.rb",
50
- "spec/grape/middleware/prefixer_spec.rb",
51
- "spec/grape/middleware/versioner_spec.rb",
52
- "spec/grape/middleware_stack_spec.rb",
53
- "spec/grape_spec.rb",
54
- "spec/spec_helper.rb"
55
- ]
56
- s.homepage = %q{http://github.com/intridea/grape}
57
- s.rdoc_options = ["--charset=UTF-8"]
58
- s.require_paths = ["lib"]
59
- s.rubygems_version = %q{1.3.7}
60
- s.summary = %q{A Ruby framework for rapid API development.}
61
- s.test_files = [
62
- "spec/grape/api_spec.rb",
63
- "spec/grape/endpoint_spec.rb",
64
- "spec/grape/middleware/auth/basic_spec.rb",
65
- "spec/grape/middleware/auth/oauth2_spec.rb",
66
- "spec/grape/middleware/base_spec.rb",
67
- "spec/grape/middleware/error_spec.rb",
68
- "spec/grape/middleware/formatter_spec.rb",
69
- "spec/grape/middleware/prefixer_spec.rb",
70
- "spec/grape/middleware/versioner_spec.rb",
71
- "spec/grape/middleware_stack_spec.rb",
72
- "spec/grape_spec.rb",
73
- "spec/spec_helper.rb"
74
- ]
6
+ Gem::Specification.new do |s|
7
+ s.name = 'grape'
8
+ s.version = Grape::VERSION
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ['Michael Bleigh']
11
+ s.email = ['michael@intridea.com']
12
+ s.homepage = 'https://github.com/ruby-grape/grape'
13
+ s.summary = 'A simple Ruby framework for building REST-like APIs.'
14
+ s.description = 'A Ruby framework for rapid API development with great conventions.'
15
+ s.license = 'MIT'
16
+ s.metadata = {
17
+ 'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
18
+ 'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
19
+ 'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
20
+ 'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}",
21
+ 'rubygems_mfa_required' => 'true'
22
+ }
75
23
 
76
- if s.respond_to? :specification_version then
77
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
78
- s.specification_version = 3
24
+ s.add_dependency 'activesupport', '>= 6.1'
25
+ s.add_dependency 'dry-types', '>= 1.1'
26
+ s.add_dependency 'mustermann-grape', '~> 1.1.0'
27
+ s.add_dependency 'rack', '>= 2'
28
+ s.add_dependency 'zeitwerk'
79
29
 
80
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
- s.add_runtime_dependency(%q<rack>, [">= 0"])
82
- s.add_runtime_dependency(%q<rack-mount>, ["~> 0.6.13"])
83
- s.add_runtime_dependency(%q<rack-jsonp>, [">= 0"])
84
- s.add_runtime_dependency(%q<json>, [">= 0"])
85
- s.add_runtime_dependency(%q<multi_json>, [">= 0"])
86
- s.add_runtime_dependency(%q<multi_xml>, [">= 0"])
87
- s.add_development_dependency(%q<rake>, [">= 0"])
88
- s.add_development_dependency(%q<jeweler>, [">= 0"])
89
- else
90
- s.add_dependency(%q<rack>, [">= 0"])
91
- s.add_dependency(%q<rack-mount>, ["~> 0.6.13"])
92
- s.add_dependency(%q<rack-jsonp>, [">= 0"])
93
- s.add_dependency(%q<json>, [">= 0"])
94
- s.add_dependency(%q<multi_json>, [">= 0"])
95
- s.add_dependency(%q<multi_xml>, [">= 0"])
96
- s.add_dependency(%q<rake>, [">= 0"])
97
- s.add_dependency(%q<jeweler>, [">= 0"])
98
- end
99
- else
100
- s.add_dependency(%q<rack>, [">= 0"])
101
- s.add_dependency(%q<rack-mount>, ["~> 0.6.13"])
102
- s.add_dependency(%q<rack-jsonp>, [">= 0"])
103
- s.add_dependency(%q<json>, [">= 0"])
104
- s.add_dependency(%q<multi_json>, [">= 0"])
105
- s.add_dependency(%q<multi_xml>, [">= 0"])
106
- s.add_dependency(%q<rake>, [">= 0"])
107
- s.add_dependency(%q<jeweler>, [">= 0"])
108
- end
30
+ s.files = Dir['lib/**/*', 'CHANGELOG.md', 'CONTRIBUTING.md', 'README.md', 'grape.png', 'UPGRADING.md', 'LICENSE', 'grape.gemspec']
31
+ s.require_paths = ['lib']
32
+ s.required_ruby_version = '>= 2.7.0'
109
33
  end
110
-
data/grape.png ADDED
Binary file
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ class API
5
+ module Helpers
6
+ include Grape::DSL::Helpers::BaseHelper
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Grape
4
+ class API
5
+ # The API Instance class, is the engine behind Grape::API. Each class that inherits
6
+ # from this will represent a different API instance
7
+ class Instance
8
+ extend Grape::Middleware::Auth::DSL
9
+ include Grape::DSL::API
10
+
11
+ class << self
12
+ attr_reader :instance, :base
13
+ attr_accessor :configuration
14
+
15
+ def given(conditional_option, &block)
16
+ evaluate_as_instance_with_configuration(block, lazy: true) if conditional_option && block
17
+ end
18
+
19
+ def mounted(&block)
20
+ evaluate_as_instance_with_configuration(block, lazy: true)
21
+ end
22
+
23
+ def base=(grape_api)
24
+ @base = grape_api
25
+ grape_api.instances << self
26
+ end
27
+
28
+ def to_s
29
+ base&.to_s || super
30
+ end
31
+
32
+ def base_instance?
33
+ self == base.base_instance
34
+ end
35
+
36
+ # A class-level lock to ensure the API is not compiled by multiple
37
+ # threads simultaneously within the same process.
38
+ LOCK = Mutex.new
39
+
40
+ # Clears all defined routes, endpoints, etc., on this API.
41
+ def reset!
42
+ reset_endpoints!
43
+ reset_routes!
44
+ reset_validations!
45
+ end
46
+
47
+ # Parses the API's definition and compiles it into an instance of
48
+ # Grape::API.
49
+ def compile
50
+ @instance ||= new # rubocop:disable Naming/MemoizedInstanceVariableName
51
+ end
52
+
53
+ # Wipe the compiled API so we can recompile after changes were made.
54
+ def change!
55
+ @instance = nil
56
+ end
57
+
58
+ # This is the interface point between Rack and Grape; it accepts a request
59
+ # from Rack and ultimately returns an array of three values: the status,
60
+ # the headers, and the body. See [the rack specification]
61
+ # (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
62
+ def call(env)
63
+ compile!
64
+ call!(env)
65
+ end
66
+
67
+ # A non-synchronized version of ::call.
68
+ def call!(env)
69
+ instance.call(env)
70
+ end
71
+
72
+ # (see #cascade?)
73
+ def cascade(value = nil)
74
+ if value.nil?
75
+ inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
76
+ else
77
+ namespace_inheritable(:cascade, value)
78
+ end
79
+ end
80
+
81
+ def compile!
82
+ return if instance
83
+
84
+ LOCK.synchronize { compile unless instance }
85
+ end
86
+
87
+ # see Grape::Router#recognize_path
88
+ def recognize_path(path)
89
+ compile!
90
+ instance.router.recognize_path(path)
91
+ end
92
+
93
+ protected
94
+
95
+ def prepare_routes
96
+ endpoints.map(&:routes).flatten
97
+ end
98
+
99
+ # Execute first the provided block, then each of the
100
+ # block passed in. Allows for simple 'before' setups
101
+ # of settings stack pushes.
102
+ def nest(*blocks, &block)
103
+ blocks.compact!
104
+ if blocks.any?
105
+ evaluate_as_instance_with_configuration(block) if block
106
+ blocks.each { |b| evaluate_as_instance_with_configuration(b) }
107
+ reset_validations!
108
+ else
109
+ instance_eval(&block)
110
+ end
111
+ end
112
+
113
+ def evaluate_as_instance_with_configuration(block, lazy: false)
114
+ lazy_block = Grape::Util::Lazy::Block.new do |configuration|
115
+ value_for_configuration = configuration
116
+ self.configuration = value_for_configuration.evaluate if value_for_configuration.try(:lazy?)
117
+ response = instance_eval(&block)
118
+ self.configuration = value_for_configuration
119
+ response
120
+ end
121
+ if base && base_instance? && lazy
122
+ lazy_block
123
+ else
124
+ lazy_block.evaluate_from(configuration)
125
+ end
126
+ end
127
+
128
+ def inherited(subclass)
129
+ super
130
+ subclass.reset!
131
+ subclass.logger = logger.clone
132
+ end
133
+
134
+ def inherit_settings(other_settings)
135
+ top_level_setting.inherit_from other_settings.point_in_time_copy
136
+
137
+ # Propagate any inherited params down to our endpoints, and reset any
138
+ # compiled routes.
139
+ endpoints.each do |e|
140
+ e.inherit_settings(top_level_setting.namespace_stackable)
141
+ e.reset_routes!
142
+ end
143
+
144
+ reset_routes!
145
+ end
146
+ end
147
+
148
+ attr_reader :router
149
+
150
+ # Builds the routes from the defined endpoints, effectively compiling
151
+ # this API into a usable form.
152
+ def initialize
153
+ @router = Router.new
154
+ add_head_not_allowed_methods_and_options_methods
155
+ self.class.endpoints.each do |endpoint|
156
+ endpoint.mount_in(@router)
157
+ end
158
+
159
+ @router.compile!
160
+ @router.freeze
161
+ end
162
+
163
+ # Handle a request. See Rack documentation for what `env` is.
164
+ def call(env)
165
+ status, headers, response = @router.call(env)
166
+ unless cascade?
167
+ headers = Grape::Util::Header.new.merge(headers)
168
+ headers.delete('X-Cascade')
169
+ end
170
+
171
+ [status, headers, response]
172
+ end
173
+
174
+ # Some requests may return a HTTP 404 error if grape cannot find a matching
175
+ # route. In this case, Grape::Router adds a X-Cascade header to the response
176
+ # and sets it to 'pass', indicating to grape's parents they should keep
177
+ # looking for a matching route on other resources.
178
+ #
179
+ # In some applications (e.g. mounting grape on rails), one might need to trap
180
+ # errors from reaching upstream. This is effectivelly done by unsetting
181
+ # X-Cascade. Default :cascade is true.
182
+ def cascade?
183
+ return self.class.namespace_inheritable(:cascade) if self.class.inheritable_setting.namespace_inheritable.key?(:cascade)
184
+ return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options)&.key?(:cascade)
185
+
186
+ true
187
+ end
188
+
189
+ reset!
190
+
191
+ private
192
+
193
+ # For every resource add a 'OPTIONS' route that returns an HTTP 204 response
194
+ # with a list of HTTP methods that can be called. Also add a route that
195
+ # will return an HTTP 405 response for any HTTP method that the resource
196
+ # cannot handle.
197
+ def add_head_not_allowed_methods_and_options_methods
198
+ # The paths we collected are prepared (cf. Path#prepare), so they
199
+ # contain already versioning information when using path versioning.
200
+ all_routes = self.class.endpoints.map(&:routes).flatten
201
+
202
+ # Disable versioning so adding a route won't prepend versioning
203
+ # informations again.
204
+ without_root_prefix_and_versioning { collect_route_config_per_pattern(all_routes) }
205
+ end
206
+
207
+ def collect_route_config_per_pattern(all_routes)
208
+ routes_by_regexp = all_routes.group_by(&:pattern_regexp)
209
+
210
+ # Build the configuration based on the first endpoint and the collection of methods supported.
211
+ routes_by_regexp.each_value do |routes|
212
+ last_route = routes.last # Most of the configuration is taken from the last endpoint
213
+ next if routes.any? { |route| route.request_method == '*' }
214
+
215
+ allowed_methods = routes.map(&:request_method)
216
+ allowed_methods |= [Rack::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Rack::GET)
217
+
218
+ allow_header = self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Rack::OPTIONS] | allowed_methods
219
+ last_route.app.options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Rack::OPTIONS)
220
+
221
+ @router.associate_routes(last_route.pattern, {
222
+ endpoint: last_route.app,
223
+ allow_header: allow_header
224
+ })
225
+ end
226
+ end
227
+
228
+ # Allows definition of endpoints that ignore the versioning configuration
229
+ # used by the rest of your API.
230
+ def without_root_prefix_and_versioning
231
+ old_version = self.class.namespace_inheritable(:version)
232
+ old_version_options = self.class.namespace_inheritable(:version_options)
233
+ old_root_prefix = self.class.namespace_inheritable(:root_prefix)
234
+
235
+ self.class.namespace_inheritable_to_nil(:version)
236
+ self.class.namespace_inheritable_to_nil(:version_options)
237
+ self.class.namespace_inheritable_to_nil(:root_prefix)
238
+
239
+ yield
240
+
241
+ self.class.namespace_inheritable(:version, old_version)
242
+ self.class.namespace_inheritable(:version_options, old_version_options)
243
+ self.class.namespace_inheritable(:root_prefix, old_root_prefix)
244
+ end
245
+ end
246
+ end
247
+ end