graphiti
graphiti copied to clipboard
Generators do not handle namespaces correctly
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
.
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 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.
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 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 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 yep, though I would recommend the accessor for this:
class Api::V1::CategoryResource < ApplicationResource
self.model = Category
# ... code ...
end
@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. 🤷♂