Description
When using camel case on endpoint names, the app throws an error while loading the grape clases and modules:
/home/rayko/.rvm/gems/ruby-2.2.5@app/gems/grape-swagger-0.20.3/lib/grape-swagger.rb:90:in `block in combine_namespace_routes': undefined method `reject' for nil:NilClass (NoMethodError)
The following method in grape-swagger.rb
def combine_routes(app, doc_klass)
app.routes.each do |route|
route_path = route.path
route_match = route_path.split(/^.*?#{route.prefix.to_s}/).last
next unless route_match
route_match = route_match.match('\/([\w|-]*?)[\.\/\(]') || route_match.match('\/([\w|-]*)$')
next unless route_match
resource = route_match.captures.first
next if resource.empty?
resource.downcase!
@target_class.combined_routes[resource] ||= []
next if doc_klass.hide_documentation_path && route.path.match(/#{doc_klass.mount_path}($|\/|\(\.)/)
@target_class.combined_routes[resource] << route
end
end
Causes to change the name that is picked up in the next step on the method:
def combine_namespace_routes(namespaces)
# iterate over each single namespace
namespaces.each do |name, namespace|
# get the parent route for the namespace
parent_route_name = name.match(%r{^/?([^/]*).*$})[1]
parent_route = @target_class.combined_routes[parent_route_name]
# fetch all routes that are within the current namespace
namespace_routes = parent_route.reject do |route|
!route_path_start_with?(route, name) || !route_instance_variable_equals?(route, name)
end
if namespace.options.key?(:swagger) && namespace.options[:swagger][:nested] == false
# Namespace shall appear as standalone resource, use specified name or use normalized path as name
identifier = if namespace.options[:swagger].key?(:name)
name.tr(' ', '-')
else
name.tr('_', '-').gsub(/\//, '_')
end
@target_class.combined_namespace_identifiers[identifier] = name
@target_class.combined_namespace_routes[identifier] = namespace_routes
# # get all nested namespaces below the current namespace
sub_namespaces = standalone_sub_namespaces(name, namespaces)
sub_routes = sub_routes_from(parent_route, sub_namespaces)
@target_class.combined_namespace_routes[identifier].push(*sub_routes)
else
# default case when not explicitly specified or nested == true
standalone_namespaces = namespaces.reject do |_, ns|
!ns.options.key?(:swagger) ||
!ns.options[:swagger].key?(:nested) ||
ns.options[:swagger][:nested] != false
end
parent_standalone_namespaces = standalone_namespaces.reject { |ns_name, _| !name.start_with?(ns_name) }
# add only to the main route if the namespace is not within any other namespace appearing as standalone resource
if parent_standalone_namespaces.empty?
# default option, append namespace methods to parent route
@target_class.combined_namespace_routes[parent_route_name] = [] unless @target_class.combined_namespace_routes.key?(parent_route_name)
@target_class.combined_namespace_routes[parent_route_name].push(*namespace_routes)
end
end
end
end
If you have an endpoint like "userCompanies", it gets mapped to "usercompanies" in combine_routes
, and combine_namespace_routes
will expect @target_class.combined_routes
to have a key "userCompanies", but since it doesn't exist, it will return nil and reject
will be executed on nil.
There was a PR about this and it was merged: https://github.com/ruby-grape/grape-swagger/pull/321/files but the change is not in master or the 0.21.0 version. I wonder what happened to it. It looks like the PR was done on an old version, since the method combine_routes
isn't present there, I suppose it was extracted as a method on a refactor after that.
What happened to this fix?