graphiti
graphiti copied to clipboard
Graphiti schema does not include endpoints with subdomain constraint
I'm trying to configure the Vandal UI for a Rails application, Vandal does not display any available endpoints.

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

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.
https://github.com/graphiti-api/graphiti/blob/aecf5647801e5e45047dc20f7ca7c220c60faad2/lib/graphiti/schema.rb#L59
https://github.com/graphiti-api/graphiti/blob/aecf5647801e5e45047dc20f7ca7c220c60faad2/lib/graphiti/schema.rb#L84-L86
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).
https://github.com/graphiti-api/graphiti/blob/19c75b58017eaf860a5160ff28c0f7dbd3f47674/lib/graphiti/resource/links.rb#L19
Maybe the resource base_url should prefix the endpoint full_path when calling Graphiti.config.context_for_endpoint from Graphiti::Schema.generate_endpoints. 🤔
Hi,
I just faced the same problem ! Thanks for your solution, it avoid me a lot of headaches !
I have one question, do you know why the links have still localhost and doesn't use my subdomain (api) ?

Also, i'm agree that we maybe should make an PR to handle this case properly, without overriding the context_for_endpoint method.