Skip to content

Commit

Permalink
Separate nested resource name (#855)
Browse files Browse the repository at this point in the history
* Fix namespaced resources seperator
The expected behavior when `Apipie.configuration.namespaced_resources?` 
is true is for a nested resource like `V1::Users::TweetsController` to
return `v1-users-tweets` however it was returning `v1userstweets`

* Refactor resource description spec

* Update `ResourceDescription`'s `name` `resource_name` and id
- Rename the `resource_name` argument to `id`, it can be missleading
- Create `name` method return a human readable resource name depending 
  on the `@id`. Example if id is `some-nested-resource` `#name` will 
  return `Some::Nested::Resource`
  • Loading branch information
PanosCodes authored Apr 10, 2023
1 parent 5fc1bf5 commit 1f28905
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 51 deletions.
12 changes: 11 additions & 1 deletion lib/apipie/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,18 @@ def get_resource_name(klass)
@controller_to_resource_id[klass]
elsif Apipie.configuration.namespaced_resources? && klass.respond_to?(:controller_path)
return nil if klass == ActionController::Base

version_prefix = version_prefix(klass)
path = klass.controller_path
path.gsub(version_prefix(klass), "").gsub("/", "-")

path =
if version_prefix == '/'
path
else
path.gsub(version_prefix, '')
end

path.gsub('/', '-')
elsif klass.respond_to?(:controller_name)
return nil if klass == ActionController::Base
klass.controller_name
Expand Down
17 changes: 10 additions & 7 deletions lib/apipie/resource_description.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,25 @@ module Apipie
class ResourceDescription

attr_reader :controller, :_short_description, :_full_description, :_methods, :_id,
:_path, :_name, :_params_args, :_returns_args, :_tag_list_arg, :_errors_args,
:_path, :_params_args, :_returns_args, :_tag_list_arg, :_errors_args,
:_formats, :_parent, :_metadata, :_headers, :_deprecated

def initialize(controller, resource_name, dsl_data = nil, version = nil)

def initialize(controller, id, dsl_data = nil, version = nil)
@_methods = ActiveSupport::OrderedHash.new
@_params_args = []
@_errors_args = []
@_returns_args = []

@controller = controller
@_id = resource_name
@_id = id
@_version = version || Apipie.configuration.default_version
@_name = @_id.humanize
@_parent = Apipie.get_resource_description(controller.superclass, version)

update_from_dsl_data(dsl_data) if dsl_data
end

def update_from_dsl_data(dsl_data)
@_name = dsl_data[:resource_name] if dsl_data[:resource_name]
@_resource_name = dsl_data[:resource_name] if dsl_data[:resource_name]
@_full_description = dsl_data[:description]
@_short_description = dsl_data[:short_description]
@_path = dsl_data[:path] || ""
Expand All @@ -61,6 +59,11 @@ def _api_base_url
@_api_base_url || @_parent.try(:_api_base_url) || Apipie.api_base_url(_version)
end

def name
@name ||= @_resource_name.presence || @_id.split('-').map(&:capitalize).join('::')
end
alias _name name

def add_method_description(method_description)
Apipie.debug "@resource_descriptions[#{self._version}][#{self._name}]._methods[#{method_description.method}] = #{method_description}"
@_methods[method_description.method.to_sym] = method_description
Expand Down Expand Up @@ -108,7 +111,7 @@ def to_json(method_name = nil, lang = nil)
:doc_url => doc_url,
:id => _id,
:api_url => api_url,
:name => @_name,
:name => name,
:short_description => Apipie.app.translate(@_short_description, lang),
:full_description => Apipie.markup_to_html(Apipie.app.translate(@_full_description, lang)),
:version => _version,
Expand Down
31 changes: 16 additions & 15 deletions spec/lib/apipie/application_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,37 @@

end

describe "get_resource_name" do
subject {Apipie.get_resource_name(Api::V2::Nested::ArchitecturesController)}
describe '.get_resource_name' do
subject(:get_resource_name) do
Apipie.get_resource_name(Api::V2::Nested::ArchitecturesController)
end

let(:base_url) { '/some-api' }

before { allow(Apipie.app).to receive(:get_base_url).and_return(base_url) }

context "with namespaced_resources enabled" do
before { Apipie.configuration.namespaced_resources = true }
context "with a defined base url" do

it "should not overwrite the parent resource" do
is_expected.not_to eq(Apipie.get_resource_name(Api::V2::ArchitecturesController))
end
after { Apipie.configuration.namespaced_resources = false }

it "returns the namespaces" do
is_expected.to eq('api-v2-nested-architectures')
end

context "with an undefined base url" do
before {allow(Apipie.app).to receive(:get_base_url).and_return(nil)}
let(:base_url) { nil }

it "should not raise an error" do
expect { Apipie.get_resource_name(Api::V2::ArchitecturesController) }.
not_to raise_error
expect { get_resource_name }.not_to raise_error
end
end

after { Apipie.configuration.namespaced_resources = false }
end

context "with namespaced_resources enabled" do
context "with namespaced_resources disabled" do
before { Apipie.configuration.namespaced_resources = false }

it "should overwrite the the parent" do
is_expected.to eq(Apipie.get_resource_name(Api::V2::ArchitecturesController))
it "returns the controller name" do
is_expected.to eq('architectures')
end
end
end
Expand Down
99 changes: 71 additions & 28 deletions spec/lib/apipie/resource_description_spec.rb
Original file line number Diff line number Diff line change
@@ -1,48 +1,91 @@
require "spec_helper"

describe Apipie::ResourceDescription do
let(:resource_description) do
Apipie::ResourceDescription.new(controller, id, dsl_data)
end

let(:controller) { ApplicationController }
let(:id) { 'dummy' }
let(:dsl_data) { ActionController::Base.send(:_apipie_dsl_data_init) }

describe "metadata" do
describe '#_methods' do
subject(:methods) { resource_description._methods }

it "should return nil when no metadata is provided" do
resource = Apipie::ResourceDescription.new(ApplicationController, "dummy", dsl_data)
expect(resource.to_json[:metadata]).to eq(nil)
end
context 'when has method descriptions' do
before do
resource_description.add_method_description(
Apipie::MethodDescription.new(:a, resource_description, dsl_data)
)
resource_description.add_method_description(
Apipie::MethodDescription.new(:b, resource_description, dsl_data)
)
resource_description.add_method_description(
Apipie::MethodDescription.new(:c, resource_description, dsl_data)
)
end

it "should return the metadata" do
meta = {
:lenght => 32,
:weight => '830g'
}
resource = Apipie::ResourceDescription.new(ApplicationController, "dummy", dsl_data.update(:meta => meta))
expect(resource.to_json[:metadata]).to eq(meta)
it 'should be ordered' do
expect(methods.keys).to eq([:a, :b, :c])
end
end

end

describe "methods descriptions" do
describe '#to_json' do
let(:json_data) { resource_description.to_json }

describe 'metadata' do
subject { json_data[:metadata] }

before(:each) do
@resource = Apipie::ResourceDescription.new(ApplicationController, "dummy")
a = Apipie::MethodDescription.new(:a, @resource, dsl_data)
b = Apipie::MethodDescription.new(:b, @resource, dsl_data)
c = Apipie::MethodDescription.new(:c, @resource, dsl_data)
@resource.add_method_description(a)
@resource.add_method_description(b)
@resource.add_method_description(c)
it { is_expected.to be_nil }

context 'when meta data are provided' do
let(:meta) { { length: 32, weight: '830g' } }
let(:dsl_data) { super().update({ meta: meta }) }

it { is_expected.to eq(meta) }
end
end

it "should be ordered" do
expect(@resource._methods.keys).to eq([:a, :b, :c])
expect(@resource.to_json[:methods].map { |h| h[:name] }).to eq(['a', 'b', 'c'])
describe 'methods' do
subject(:methods_as_json) { json_data[:methods] }

context 'when has method descriptions' do
before do
resource_description.add_method_description(
Apipie::MethodDescription.new(:a, resource_description, dsl_data)
)
resource_description.add_method_description(
Apipie::MethodDescription.new(:b, resource_description, dsl_data)
)
resource_description.add_method_description(
Apipie::MethodDescription.new(:c, resource_description, dsl_data)
)
end

it 'should be ordered' do
expect(methods_as_json.map { |h| h[:name] }).to eq(['a', 'b', 'c'])
end
end
end
end

describe 'name' do
subject { resource_description.name }

it { is_expected.to eq('Dummy') }

it "should be still ordered" do
expect(@resource._methods.keys).to eq([:a, :b, :c])
expect(@resource.to_json[:methods].map { |h| h[:name] }).to eq(['a', 'b', 'c'])
context 'when given id contains dashes' do
let(:id) { 'some-nested-resource' }

it { is_expected.to eq('Some::Nested::Resource') }
end

context 'when resource_name is given' do
let(:resource_name) { 'Some-Resource' }
let(:dsl_data) { super().merge!(resource_name: 'Some-Resource') }

it { is_expected.to eq(resource_name) }
end
end
end

0 comments on commit 1f28905

Please sign in to comment.