Maybe this isn't so much a bug, but more a developer experience problem: if you've setup a new rails 5.1 application with:
rails new graphql-project --api
And then followed the addition of graphql to your Gemfile and run rails generate graphql:install, you can't straight away start the server, as you'll be missing graphiql-rails dependency. So, you go "bundle install, that'll fix it", you do this, and you can now start the server.
Now, as you've seen some GraphQL implementations, you know what graphiql is, so you go to http://localhost:3000/graphiql. And all you see is "Loading..." in the browser.
The logs show:
rails s master*
=> Booting Puma
=> Rails 5.1.1 application starting in development on http://localhost:3000
=> Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.9.0 (ruby 2.4.1-p111), codename: Private Caller
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://0.0.0.0:3000
Use Ctrl-C to stop
Started GET "/graphiql" for 127.0.0.1 at 2017-06-07 03:08:33 +0200
Processing by GraphiQL::Rails::EditorsController#show as HTML
Parameters: {"graphql_path"=>"/graphql"}
Rendering /Users/micheil/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/graphiql-rails-1.4.1/app/views/graphiql/rails/editors/show.html.erb
Rendered /Users/micheil/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/graphiql-rails-1.4.1/app/views/graphiql/rails/editors/show.html.erb (2.9ms)
Completed 200 OK in 272ms (Views: 25.6ms)
Started GET "/stylesheets/graphiql/rails/application.css" for 127.0.0.1 at 2017-06-07 03:08:33 +0200
ActionController::RoutingError (No route matches [GET] "/stylesheets/graphiql/rails/application.css"):
actionpack (5.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:63:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.1) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
railties (5.1.1) lib/rails/engine.rb:522:in `call'
puma (3.9.0) lib/puma/configuration.rb:224:in `call'
puma (3.9.0) lib/puma/server.rb:602:in `handle_request'
puma (3.9.0) lib/puma/server.rb:435:in `process_client'
puma (3.9.0) lib/puma/server.rb:299:in `block in run'
puma (3.9.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'
Started GET "/javascripts/graphiql/rails/application.js" for 127.0.0.1 at 2017-06-07 03:08:33 +0200
ActionController::RoutingError (No route matches [GET] "/javascripts/graphiql/rails/application.js"):
actionpack (5.1.1) lib/action_dispatch/middleware/debug_exceptions.rb:63:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.1) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.1) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.1) lib/rails/rack/logger.rb:24:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.3) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.1) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.1) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.3) lib/rack/sendfile.rb:111:in `call'
railties (5.1.1) lib/rails/engine.rb:522:in `call'
puma (3.9.0) lib/puma/configuration.rb:224:in `call'
puma (3.9.0) lib/puma/server.rb:602:in `handle_request'
puma (3.9.0) lib/puma/server.rb:435:in `process_client'
puma (3.9.0) lib/puma/server.rb:299:in `block in run'
puma (3.9.0) lib/puma/thread_pool.rb:120:in `block in spawn_thread'
Which, if you're just switching back to rails after a break, looks rather scary. But it's not really. It's just that graphiql-rails isn't compatible with api only projects as it requires all the asset middleware to compile the CSS and JavaScript.
1) Detect if the project is API only on rails g graphql:install (I'm not sure if this is possible)
If the project is API Only, automatically skip installing and adding the route for graphiql; Perhaps even suggest using the GraphQL Electron app or GraphQL-ide.
If the project is not API Only (or if this can't be detected), prompt the user as to whether they'd like to install graphiql-rails, state that it isn't api-only compatible, and tell them that they'll need to run a bundle install afterwards.
I feel like yes, these may be low hanging fruits, but those just go to make the first-use experience amazing, rather than a little confusing.
Would be happy to do a pull request if these are changes the community would find helpful.
I think all the changes you outlined would be great! Sorry for the hangups, I'm still getting the hang of Rails generators 😅
Apparently there's already an option which is --skip_graphiql to rails g graphql:install, which skips graphiql. Will look for a way to automatically detect --api_only apps
I've now got the following:
api-only $ rails g graphql:install
create app/graphql/mutations
create app/graphql/mutations/.keep
create app/graphql/types
create app/graphql/types/.keep
create app/graphql/types/query_type.rb
create app/graphql/api_only_schema.rb
create app/controllers/graphql_controller.rb
route post "/graphql", to: "graphql#execute"
Skipping install of graphiql, as this rails project is API only
You may wish to use GraphiQL.app for development: https://github.com/skevy/graphiql-app
api-only $
The message about graphiql-app does not get printed if you're using --skip-graphiql
For a normal rails app, you'll get:
normal $ rails g graphql:install
create app/graphql/mutations
create app/graphql/mutations/.keep
create app/graphql/types
create app/graphql/types/.keep
create app/graphql/types/query_type.rb
create app/graphql/normal_schema.rb
create app/controllers/graphql_controller.rb
route post "/graphql", to: "graphql#execute"
gemfile graphiql-rails
route graphiql-rails
Gemfile has been updated, make sure you `bundle install`.
normal $
Note that I've also changed the output of route in the above to not actually print the code for the route, which looks rather messy in the terminal, and instead it just prints graphiql-rails, that's done with:
# This is a little cheat just to get cleaner shell output:
log :route, 'graphiql-rails'
shell.mute do
route(GRAPHIQL_ROUTE)
end
So, I'm still doing all the same logic as normal, I'm just not logging the messages from route. Open to better suggestions here.
The "Gemfile" message is what I've gone with instead of automatically doing a bundle install.
Those changes look great! Bravo on the route clean-up, I wasn't sure what to do there.
For options.api?, is that something which Rails provides for you, or is it set when the user passes graphql:install --api ?
Both! Essentially I think if you specify a class_option as something that exists in this block, then you get them from rails — it's kind weird magic: https://github.com/rails/rails/blob/master/railties/lib/rails/generators.rb#L49-L81
api-only $ rails g graphql:install
From: /Users/emelia/Work/UnobviousTechnology/repos/graphql-ruby/lib/generators/graphql/install_generator.rb @ line 87 Graphql::Generators::InstallGenerator#create_folder_structure:
82: mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
83: end
84: RUBY
85:
86: def create_folder_structure
=> 87: binding.pry
88:
89: create_dir("app/graphql/types")
90: template("schema.erb", schema_file_path)
91:
92: # Note: You can't have a schema without the query type, otherwise introspection breaks
[1] pry(#<Graphql::Generators::InstallGenerator>)> options
=> {"skip_keeps"=>false, "skip_graphiql"=>false, "relay"=>false, "batch"=>false, "api"=>true}
[2] pry(#<Graphql::Generators::InstallGenerator>)>
Wow, TIL! That's a nice feature. I had a hard time with generator docs, but it seems like there's a lot of good stuff there!
now I know why it's not installed by default, thanks for this great discussions.
btw, is there a way to install graphiql in API-only (development mode of cuz!) rails application? looks like I have to precompile css / js files and save them in the right path tho
@huang47 To run graphiql in Rails 5.1.5 api_only, Ruby 2.5.0 - just uncomment require 'sprockets/railtie' in application.rb. There is no need to set config.api_only to false.
Then go to http://localhost:3000/graphiql.
@BlookHo 's suggestion works!
Most helpful comment
@huang47 To run
graphiqlinRails 5.1.5 api_only,Ruby 2.5.0- just uncommentrequire 'sprockets/railtie'inapplication.rb. There is no need to setconfig.api_onlytofalse.Then go to
http://localhost:3000/graphiql.