graphiti icon indicating copy to clipboard operation
graphiti copied to clipboard

Generators do not handle namespaces correctly

Open aemadrid opened this issue 5 years ago • 7 comments

When using the generator it creates invalid ruby code for specs and bad routes. For example:

rails g graphiti:resource LocaL::User username:string

Generates specs with fixtures names :local/user and a route to local_users instead of local/users.

aemadrid avatar May 09 '19 21:05 aemadrid

I have a similar issue that I'm a bit confused with - you can define an API endpoint namespace in your resource (self.endpoint_namespace = '/api/v2'), but then when generating controllers for resources they are dumped into the root /app/controllers/ folder.

I am aware I can namespace the resource, e.g. Api::V2::Profile, but then it requires a corresponding model with the namespace, whereas my model is simply Profile. I know I can set it up this way without the generators, but it would be nice if the generator could somehow handle this case.

Is there a suggested path forward, or better way of going about namespacing the controller endpoints?

geeosh avatar May 11 '19 15:05 geeosh

@geeosh I think there's an improvement to the generators we can make. That said, the "endpoint namespace" is somewhat orthagonal - I personally route to my APIs by URL prefix (/news_api/v1 routes to news_api, with no namespacing).

We can improve the generators, and perhaps need a separate configuration option in graphiticfg.yml - something like module_namespace for this case.

richmolj avatar May 15 '19 12:05 richmolj

I'm also having this problem, can you work around it?

is this method that deals with this? https://github.com/graphiti-api/graphiti/blob/master/lib/graphiti/resource/configuration.rb#L48

danieldocki avatar May 22 '19 19:05 danieldocki

@danieldocki it's not really an issue with Graphiti itself, but the code the generators generate. If you used the generators and then manually fixed routes and factories, or wrote the code manually, it should work. We should certainly improve the generators though.

richmolj avatar May 22 '19 20:05 richmolj

@richmolj Regarding routes yes I did manually, but in relation to the resource namespace?

namespace :api, constraints: { format: :jsonapi } do
  namespace :v1 do
    resources :categories, except: %i[new edit]
  end
end
class Api::V1::CategoryResource < ApplicationResource
  attribute :name, :string
  attribute :created_at, :datetime, writable: false
  attribute :updated_at, :datetime, writable: false
end
irb(main):003:0> Api::V1::CategoryResource.all.data
Traceback (most recent call last):
        1: from (irb):3
Graphiti::Errors::ModelNotFound (Graphiti::Errors::ModelNotFound)

to make it work I override the method model

class Api::V1::CategoryResource < ApplicationResource
  attribute :name, :string
  attribute :created_at, :datetime, writable: false
  attribute :updated_at, :datetime, writable: false

  def model
    Category
  end
end

Is it okay to do this?

danieldocki avatar May 23 '19 19:05 danieldocki

@danieldocki yep, though I would recommend the accessor for this:

class Api::V1::CategoryResource < ApplicationResource
  self.model = Category
  # ... code ...
end

richmolj avatar May 24 '19 13:05 richmolj

@danieldocki

I solved this using a base V1::ApiResource that all V1 resources extend (instead of root ApplicationResource), which overrides the #infer_model method.

# resources/v1/api_resource.rb
class V1::ApiResource < ApplicationResource
  self.abstract_class = true

  def self.infer_model
    name&.split('::').last&.gsub("Resource", "")&.safe_constantize
  end
end

# resources/v1/category_resource.rb
class V1::CategoryResource < V1::ApiResource
  # self.model = Category  # <-- not needed

  attribute :name, :string
  attribute :created_at, :datetime, writable: false
  attribute :updated_at, :datetime, writable: false
end

FWIW, I didn't namespace with Api, in my case, since resources were only used in that context. 🤷‍♂

zpencerq avatar Jul 31 '19 17:07 zpencerq