Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem in namespacing controllers #445

Open
danjvarela opened this issue Jan 23, 2023 · 2 comments
Open

Problem in namespacing controllers #445

danjvarela opened this issue Jan 23, 2023 · 2 comments

Comments

@danjvarela
Copy link

danjvarela commented Jan 23, 2023

What I hope to achieve

Have routes mapped to namespaced controllers (Api::V1::NotesController) much like the one below:

image

Attempted solution:

  1. Create new rails app: rails new sample-graphiti-api --api -m https://www.graphiti.dev/template
  2. Press <ENTER> if asked for the namespace (default is /api/v1)
  3. rails generate model Note content:string
  4. rails generate graphiti:resource note content:string created_at:datetime (rails generate graphiti:resource api/v1/note content:string created_at:datetime doesn't work so we do it manually)
  5. Move app/resources/note_resource.rb to app/resources/api/v1/note_resource.rb and change NoteResource to Api::V1::NoteResource
class Api::V1::NoteResource < ApplicationResource
  attribute :content, :string
  attribute :created_at, :datetime, writable: false
end
  1. Move app/controllers/notes_controller.rb to app/controllers/api/v1/note_resource.rb and change NotesController to Api::V1::NotesController. Also, change all occurrences of NoteResource to Api::V1::NoteResource. File should look like this:
class Api::V1::NotesController < ApplicationController
  def index
    notes = Api::V1::NoteResource.all(params)
    respond_with(notes)
  end

  def show
    note = Api::V1::NoteResource.find(params)
    respond_with(note)
  end

  def create
    note = Api::V1::NoteResource.build(params)

    if note.save
      render jsonapi: note, status: 201
    else
      render jsonapi_errors: note
    end
  end

  def update
    note = Api::V1::NoteResource.find(params)

    if note.update_attributes
      render jsonapi: note
    else
      render jsonapi_errors: note
    end
  end

  def destroy
    note = Api::V1::NoteResource.find(params)

    if note.destroy
      render jsonapi: { meta: {} }, status: 200
    else
      render jsonapi_errors: note
    end
  end
end
  1. Change the routes to:
Rails.application.routes.draw do
  namespace :api do
    namespace :v1 do
      resources :notes, defaults: { format: :jsonapi }
    end
  end
end
  1. Run the migrations and start the server
  2. Do a GET /api/v1/notes. An error occurs:

Graphiti::Errors::InvalidEndpoint (          Api::V1::NoteResource cannot be called directly from endpoint /api/v1/notes#index!

          Either set a primary endpoint for this resource:

          primary_endpoint '/my/url', [:index, :show, :create]

          Or whitelist a secondary endpoint:

          secondary_endpoint '/my_url', [:index, :update]

          The current endpoints allowed for this resource are: [{:path=>:"/api/v1/notes", :full_path=>:"/api/v1/api/v1/notes", :url=>:"http://localhost:3000/api/v1/api/v1/notes", :actions=>[:index, :show, :create, :update, :destroy]}]
):


@danjvarela
Copy link
Author

So far, the only workaround that works for me is overriding the endpoint_namespace and model of Api::V1::NoteResource like so:

class Api::V1::NoteResource < ApplicationResource
  self.endpoint_namespace = ''
  self.model = Note
  attribute :content, :string
  attribute :created_at, :datetime, writable: false
end

@bilouw
Copy link

bilouw commented Mar 7, 2023

Hi,

I used the same workaround ! But i did self.endpoint_namespace = '' in ApplicationRessource that inherit from Graphiti::Resource. Then, all my resource inherit from ApplicationResource so i don't need to override endpoint_namespace in every resources.

Also, you don't need to override self.model in every resource. In ApplicationResource again, override the infer_model method with something like this:

# Extends our Graphiti needs
class << self
  def infer_model
    name&.split('::')&.last&.sub("Resource", "")&.safe_constantize
  end
end

You may need to override others to make it work !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants