lib/grape/api/instance.rb in grape-1.3.3 vs lib/grape/api/instance.rb in grape-1.4.0

- old
+ new

@@ -190,41 +190,19 @@ # For every resource add a 'OPTIONS' route that returns an HTTP 204 response # with a list of HTTP methods that can be called. Also add a route that # will return an HTTP 405 response for any HTTP method that the resource # cannot handle. def add_head_not_allowed_methods_and_options_methods - routes_map = {} - - self.class.endpoints.each do |endpoint| - routes = endpoint.routes - routes.each do |route| - # using the :any shorthand produces [nil] for route methods, substitute all manually - route_key = route.pattern.to_regexp - routes_map[route_key] ||= {} - route_settings = routes_map[route_key] - route_settings[:pattern] = route.pattern - route_settings[:requirements] = route.requirements - route_settings[:path] = route.origin - route_settings[:methods] ||= [] - if route.request_method == '*' || route_settings[:methods].include?('*') - route_settings[:methods] = Grape::Http::Headers::SUPPORTED_METHODS - else - route_settings[:methods] << route.request_method - end - route_settings[:endpoint] = route.app - end - end - + versioned_route_configs = collect_route_config_per_pattern # The paths we collected are prepared (cf. Path#prepare), so they # contain already versioning information when using path versioning. # Disable versioning so adding a route won't prepend versioning # informations again. without_root_prefix do without_versioning do - routes_map.each_value do |config| - methods = config[:methods] - allowed_methods = methods.dup + versioned_route_configs.each do |config| + allowed_methods = config[:methods].dup unless self.class.namespace_inheritable(:do_not_route_head) allowed_methods |= [Grape::Http::Headers::HEAD] if allowed_methods.include?(Grape::Http::Headers::GET) end @@ -239,10 +217,29 @@ end end end end + def collect_route_config_per_pattern + all_routes = self.class.endpoints.map(&:routes).flatten + routes_by_regexp = all_routes.group_by { |route| route.pattern.to_regexp } + + # Build the configuration based on the first endpoint and the collection of methods supported. + routes_by_regexp.values.map do |routes| + last_route = routes.last # Most of the configuration is taken from the last endpoint + matching_wildchar = routes.any? { |route| route.request_method == '*' } + { + options: {}, + pattern: last_route.pattern, + requirements: last_route.requirements, + path: last_route.origin, + endpoint: last_route.app, + methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method) + } + end + end + # Generate a route that returns an HTTP 405 response for a user defined # path on methods not specified def generate_not_allowed_method(pattern, allowed_methods: [], **attributes) supported_methods = if self.class.namespace_inheritable(:do_not_route_options) @@ -250,10 +247,9 @@ else Grape::Http::Headers::SUPPORTED_METHODS_WITHOUT_OPTIONS end not_allowed_methods = supported_methods - allowed_methods return if not_allowed_methods.empty? - @router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes) end # Allows definition of endpoints that ignore the versioning configuration # used by the rest of your API.