Skip to content

Graphiti schema does not include endpoints with subdomain constraint  #412

Description

@masterT

I'm trying to configure the Vandal UI for a Rails application, Vandal does not display any available endpoints.

Screen Shot 2022-04-19 at 15 05 37

The schema.json that Vandal fetched does not contain any endpoints.

Screen Shot 2022-04-19 at 15 11 48

I'm using a subdomain constraint on the route of my endpoints.

# config/routes.rb

constraints subdomain: 'api' do
  namespace :v3, defaults: { format: :jsonapi } do
    mount VandalUi::Engine, at: '/vandal'

    resources :accounts, only: %i[index show]
  end
end

I dig a little in the source code, and realise that the Graphiti::Schema.generate uses the Graphiti.config.context_for_endpoint.

next unless (ctx = context_for(e[:full_path], a))

def context_for(path, action)
Graphiti.config.context_for_endpoint.call(path.to_s, action)
end

Which is configured by graphiti-rails in lib/graphiti/rails/railtie.rb#L120-L139.

Graphiti.config.context_for_endpoint = ->(path, action) {
  method = :GET
  case action
    when :show then path = "#{path}/1"
    when :create then method = :POST
    when :update
      path = "#{path}/1"
      method = :PUT
    when :destroy
      path = "#{path}/1"
      method = :DELETE
  end


  route = begin
            ::Rails.application.routes.recognize_path(path, method: method)
          rescue
            nil
          end
  "#{route[:controller]}_controller".classify.safe_constantize if route
}

The problem is that in order for recognize_path to return the route for a subdomain constraint, the path should include the host (ex: http://api.example.com/v1) instead of the path (ex: /v1).

This can be easily fixed by changing the Graphiti.config.context_for_endpoint in a Rails initializer (ex: config/initializers/graphiti.rb).

Graphiti.config.context_for_endpoint = ->(path, action) {
  method = :GET
  case action
    when :show then path = "#{path}/1"
    when :create then method = :POST
    when :update
      path = "#{path}/1"
      method = :PUT
    when :destroy
      path = "#{path}/1"
      method = :DELETE
  end

+  # Add host to the path to resolve route with subdomain constraint.
+  path = 'http://api.example.com' + path.to_s

  route = begin
            ::Rails.application.routes.recognize_path(path, method: method)
          rescue
            nil
          end
  "#{route[:controller]}_controller".classify.safe_constantize if route
}

After this change, the schema contains the expected endpoints.

{
  # ...
  :endpoints => {
    :"/v3/accounts" => {
      :actions => {
        :index => {
          :resource => "V3::AccountResource"
        },
         :show => {
          :resource => "V3::AccountResource"
        }
      }
    }
  }
}

I'm wondering if some changes should be made (gem graphiti, gem graphiti-rails) so the this is handled by default. I'm opening an issue to document the issue, but also to discuss potential changes to improve Graphiti. 🙂

I know that a Resource has a base_url (through the module Graphiti::Links).

Maybe the resource base_url should prefix the endpoint full_path when calling Graphiti.config.context_for_endpoint from Graphiti::Schema.generate_endpoints. 🤔

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugVerified to reproduce; see needs-repro for unconfirmedneeds reproNeeds a reproduction before triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions