samesystem / graphql_rails Goto Github PK
View Code? Open in Web Editor NEWGraphQL on Rails. Write GraphQL server side in rails way
Home Page: https://samesystem.github.io/graphql_rails
License: MIT License
GraphQL on Rails. Write GraphQL server side in rails way
Home Page: https://samesystem.github.io/graphql_rails
License: MIT License
Now it's only posible to specify enums for input types like this:
class MoModel
graphql.input do |c|
c.attribute(:field, enum: %i[value1 value2]
end
end
but it's not possible to specify enum values via permit
method. It would be nice to be able to do something like this:
class MyModel
graphql do |c|
c.attribute(:field).permit_input(:some_attribute, enum: %i[value1 value2])
end
end
or
class MyModel
graphql do |c|
c.attribute(:field).permit_enum(:some_attribute, values: %i[value1 value2])
end
end
or maybe just having easy way to define enum types easy:
MyEnum = GraphqlRails::Enum.new(values: %i[value1 value2])
class MyModel
graphql do |c|
c.attribute(:field).permit_input(:some_attribute, type: 'MyEnum')
end
end
It would be cool if that can be done on controller attributes too.
currently Controller#before_filter
is applied for all actions and there is no way how to whitelist or blacklist them
I just discovered this gem through rubygems. I really like the simplicity and familiarity of using this for rails developers. :)
Good job! 👍
I'm interested to see how I can use this to get nested queries like this:
{
users(first:10) {
email
groups(first:10) {
title
description
members(first:5) {
email
}
}
}
}
Is this automatically available based on ID type (for example from User has_many :groups, through: :group_memberships
)?
Thanks!
Here is the problem:
resources :messages do
query :info
end
this generates field infoMessages
. It would be nice to add info
part to the end of field, so it would be messagesInfo
instead. My idea is to have something like this:
resources :messages do
query :info, suffix: true
end
Although it's possible to decorate record in calendar action in most cases, but there are no easy way how to do this when return type is Connection
(paginated)
this one crashes:
class ItemsController < GraphqlRails::Controller
action(:some_action)
end
GraphqlRails::Router.draw do
resources :items do
mutation(:someAction)
end
this one crashes too:
class ItemsController < GraphqlRails::Controller
action(:someAction)
end
GraphqlRails::Router.draw do
resources :items do
mutation(:some_action)
end
this one is ok:
class ItemsController < GraphqlRails::Controller
action(:some_action)
end
GraphqlRails::Router.draw do
resources :items do
mutation(:some_action)
end
this one is ok too:
class ItemsController < GraphqlRails::Controller
action(:someAction)
end
GraphqlRails::Router.draw do
resources :items do
mutation(:someAction)
end
GraphqlRails should allow to use mixed names too or at least it should crash with clear message
The issue occured when I was trying to migrate from graphql
and start using graphql_rails
gem.
graphql
gem generates schema name from Rails app name with "#{Rails.application.class.parent_name}Schema"
. (Even though you can pass an option as a schema name but it is not mentioned in documentation for some reason)
And graphql_rails
builds schema name from options passed to schema:dump
task or takes an option and [['graphql', name.presence, 'schema'].compact.join('_')
](https://github.com/samesystem/graphql_rails/blob/master/lib/graphql_rails/tasks/schema.rake#L23)
So when I try to dump a schema when using graphql_rails
it doesn't find my schema file and throws an error
RET bundle exec rake graphql_rails:schema:dump machik
rake aborted!
NoMethodError: undefined method `to_definition' for nil:NilClass
/home/jokubas/work/bastardos/rails/graphql_rails/lib/graphql_rails/tasks/schema.rake:17:in `call'
/home/jokubas/work/bastardos/rails/graphql_rails/lib/graphql_rails/tasks/schema.rake:9:in `call'
We need to unify graphql
and graphql_rails
schema name generating
Types::ExampleType.to_non_null_type.to_list_type.to_non_null_type
will end up looking as [ExampleType!]
in schema. This is not how it is supposed to work. A quick workaround is to add to_graphql
which would then build correct graphql definition type, but that's a workaround rather than a good solution.
class ItemsFilterInput
includes GraphqlRails::Model
graphql.input do |c|
c.attribute(:item_name).type(:string)
end
end
cłass MyModelWithInputs
includes GraphqlRails::Model
graphql do |c|
c.attribute(:items).permit(filter: 'ItemsFilterInput')
end
def items(filter: nil)
puts filter
end
end
the problem with this code is that argument filter
in MyModelWithInputs#items
method is graphql object and not hash. This is not right - it should be Hash
Ir would be nice to have global router so we do not need to assign it's value to some constant
DEPRECATION WARNING: ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead. (called from parameter_filter_class at /path/graphql_rails/lib/graphql_rails/controller/log_controller_action.rb:67)
It would be great to have standardized crud actions, like:
Currently we can only define enum as non-list type via:
attribute(...).enum(%i[val1 val2])
But there is no way how to define enum list. Not sure for best DSL yet, but I'm considering something like that
attribute(...)
.enum(%i[val1 val2], list: true, required_inner: true, required_list: true)
or
attribute(...).enum_list(%i[val1 val2], required_inner: true, required_list: true)
Also we need to make sure that it will play nice with #152 too
it would be nice to define enum types directly in model, something like this:
class User
graphql do |c|
c.attribute :type, enum: %i[ADMIN MANAGER GUEST]
end
end
Currently, we're not able to pass any options for attribute defined inside GraphqlRails::Model
, e.g:
c.attribute :name, camelize: false
is not an option. However, that's possible from the controller definition.
It would be extremely helpful if this was also available in models since that's how the majority of definitions are done.
graphql-ruby already has support for GraphQL::Types::ISO8601DateTime
and GraphQL::Types::JSON
(even tough they are not default GraphQL types). I would suggest to include them in graphql_rails, so instead of
action(:create).permit(date: GraphQL::Types::ISO8601DateTime, data: GraphQL::Types::JSON)
we could use
action(:create).permit(date: :date_time, data: :json)
It does not make sense to have empty enum, but in case it happens, graphql_rails raises exeption which sounds like this: GraphQL::RequiredImplementationMissingError: Anonymous class should declare a
graphql_name`. What is should raise is something like this:
GraphRails::InvalidEnumError enum <ENUM_NAME> defined in <CLASS_NAME> must have at least one option`
graphql-ruby moved to new, class-based DSL witch makes working with it easier. We already use this DSL in some places, but in other places we are still using old style DSL. Those DSL's are not very compatible so it slows down development of a new features
It would be nice to type rake graphql_rails:install
which generates:
app/graphql/graphql_router.rb
)app/controllers/graphql_controller.rb
)app/controllers/graphql/application_graphql_controller.rb
). Bonus - make it mountableWith GraphqlRails it's possible to log actions to kibana, sentry and other monitoring tools. We need to add those loggers as part of GraphqlRails gem (at least for now)
Hello. I can't quite tell if this library will infer any controller actions and model based on conventions or if I am supposed to always specify it.
resources :users
We could infer:
model('User')
action(:show).returns_single
action(:index).returns_list
action(:create).returns_single
action(:update).returns_single
action(:destroy).returns_single
I don't see these lines in the example, but they appear to be required?
It's easy to do it manually, but in most cases it would be nice to do so by default. Manual way:
class ApplicationGraphqlController < GraphqlRails::Controller
protected
def params
super.deep_transform_keys(&:underscore).with_indifferent_access
end
end
Would be nice to work on ruby 3.0
It should be possible to generate input types too. One of the options might be to generate nested permit params on controller level
class UsersController < GrapqhlRails::Controller
action(:create)
.permit(input: [:name!, :surname!, { friends_count: :int }])
action(:update)
.permit(input: [:name!, :surname!, { friends_count: :int }])
.permit(id!)
end
this would generate two input types based on controller UserCreateInputType
and UserUpdateInputType
Hi 👋 this project looks awesome. I want to test it out, but unfortunately I'm having an issue after install. The generator does not appear to be available:
Could not find generator 'graphql_rails:install'. Maybe you meant 'graphql:install', 'responders:install' or 'pundit:install'
Run `rails generate --help` for more options.
I confirmed that it is not in my list when I do rails generate
.
Bundle confirms the gem is installed:
Using graphql_rails 0.8.0
This is a Rails 5.2 app.
It would be nice to define multiple routers as groups:
Router.draw do
resources :shared_users
group :web do
resources :web_users
end
group :mobile do
resources :mobile_users
end
end
It would be nice to if we could pass additional arguments to decorator when doing decorate(object, with: Decorator)
. Improved dsl could look like this:
decorate(object, arg1, arg2).with(Decorator)
In simple case this could be converted to Decorator.new(object, arg1, arg2)
It's possible to customize errors for each project by extending GraphqlRails::Error
class, but it's not very intuitive and it's not documented. We need to do both: improve errors API and document it
It would be great if this DSL supported model types, and not only scalar ones.
graphql do |c|
c.attribute :images, type: '[Image]'
end
It returns an error message claiming that type [Image]
does not exist.
It should allow referencing other models as well, so we can chain types as deeply as we want.
With #116 it's now possible to have multiple graphql schemas using groups
method. It would be nice to have such thing on model level, something like this:
class User
include GraphqlRails::Model
graphql do |c|
c.attribute :secret, group: :internal
c.group(:testing) do |testing|
testing.attribute :testing_id
end
end
end
Using input types in controllers is very limited. It's hard to add required input, also there is no way to add description for each input. I suggest to add permit_input
method which allows to add only one field at the time, but allows to pass various options. Here is an example:
class User
graphql.input(:create_user) do |c|
end
end
class UsersController < GraphqlRails:Controller
action(:create)
.permit_input(:input, type: `User!', input_for: 'create_user', description: '...')
end
another options would be to extend existing permit
method and allow to accept hash, like this:
class UsersController < GraphqlRails:Controller
action(:create)
.permit(input: { type: `User!', input_for: 'create_user', description: '...' })
end
at the moment i can think of few options:
input_for
which uses named inputtype
which can use string instead of class (to avoid unnecessary class load)description
- small contribute to documentationThis raises exception:
class UsersController < GraphqlRails::Controller
end
GraphqlRails::Router.draw do
query :something, to: 'users#non_existing_action'
end
It would be nice to receive error which says something like Route points to non existing action
instead of undefined method [] for nil class
Currently when we test graphql controller we do not validate input type. So test will pass with nil
attributes even if schema says that it's not allowed to provide nil
value. We need to find a way how to take in to account permitted params in tests
Deletion of ExampleUsersController
and resources :example_users
route causes strange error
Completed 500 Internal Server Error in 5ms (ActiveRecord: 0.0ms | Allocations: 2230)
RuntimeError (Unexpected parent_type: ):
app/controllers/graphql_controller.rb:7:in `execute'
Other controllers are untouched.
Except that I have new graphql controller which is app/controllers/sessions_controller.rb
The same problem also occurs if all graphql controllers are deleted and graphql_router
is empty
GraphqlRouter = GraphqlRails::Router.draw do
scope module: :graphql do
end
end
After upgrade to Rails 6.1 we getting error :
NameError:
rails_1 | uninitialized constant ActionDispatch::Http::ParameterFilter
rails_1 | Did you mean? ActionDispatch::Http::Parameters
rails_1 | # /data/bundles/base/ruby/2.7.0/gems/graphql_rails-1.1.0/lib/graphql_rails/controller/log_controller_action.rb:54:in `filtered_params'
rails_1 | # /data/bundles/base/ruby/2.7.0/gems/graphql_rails-1.1.0/lib/graphql_rails/controller/log_controller_action.rb:40:in `default_payload
....
which comes from https://github.com/samesystem/graphql_rails/blob/master/lib/graphql_rails/controller/log_controller_action.rb#L54 .
I found this from previous Rails
ParameterFilter inherits from ActionDispatch::Http::ParameterFilter which will be removed from Rails 6.1:
DEPRECATION WARNING: ActionDispatch::Http::ParameterFilter is deprecated and will be removed from Rails 6.1. Use ActiveSupport::ParameterFilter instead.
It's opinionated, but this gem is all about it. By default when we returning paginated response we return cursor which is index_number converted to base64. I think this adds unnecessary complexity. We should stop converting it into base64. Here is the way:
module Graphql
module PlainCursorEncoder
def self.encode(plain, _nonce)
plain
end
def self.decode(plain, _nonce)
plain
end
end
end
GraphqlRails::Router.draw do
cursor_encoder(Graphql::PlainCursorEncoder)
# ...
end
now we need to find a way how to make this default
DEPRECATION WARNING: GraphQL::InputObjectType.define will be removed in GraphQL-Ruby 2.0; use a class-based definition instead. See https://graphql-ruby.org/schema/class_based_api.html.
Since we can have two objects that obtain each other, we can in theory end up with very deep query depth, as you could do as seen below, where you first request posts, which includes users, which again includes posts.
It makes sense to be able to do this though, as it minimises how many requests are needed, but it can also be very expensive if not handled correctly.
Since graphQL is only used internally, we’ll initially support these sort of circular dependencies.
Currently "cursor" is String but it's value is always integer. It does not make sense
when testing paginated action which does not ave paginated(max_page_size: 123)
I get error
NoMethodError:
undefined method `default_max_page_size' for #<GraphqlRails::RSpecControllerHelpers::FakeSchema:0x00005631ba4d8e00>
Lets assume I have two models Foo
and Bar
class Foo < ApplicationRecord
...
has_many :bars
...
graphql do |c|
c.attribute :id, type: :id
...
c.attribute :bars, type: Bar.graphql.graphql_type.to_list_type
end
end
class Bar < ApplicationRecord
...
has_many :foos
...
graphql do |c|
c.attribute :id, type: :id
...
c.attribute :foos, type: Foo.graphql.graphql_type.to_list_type
end
end
I would expect bars
to appear as Foo
type's attributes, but it doesn't, unless I remove c.attribute :foos, type: Foo.graphql.graphql_type.to_list_type
from Bar
's graphql attributes definition, or change dynamic type definition Bar.graphql.graphql_type.to_list_type
to '[Bar]'
When working with multithreaded server, schema generation seems to be generated faulty in one of the async requests.
Reproduction steps
graphql
gem indicating that some types are without fields.Field Query.users's return type is invalid: User must define at least 1 field. 0 defined.
As this is tricky to reproduce, you can do it from rails console too.
5.times { Thread.new { ::GraphqlRouter.graphql_schema } }
. One of the threads will fail and throw an error.
It would be nice if we could provide model for each controller. In most cases I endup writting something like this:
class MyController < Graphql::Controller
action(:index).returns('[MyCustomClass!]!')
action(:show).returns('MyCustomClass!')
action(:update).returns('MyCustomClass!')
end
I think we could add model
config option for controller, like this:
class MyController < Graphql::Controller
model 'MyCustomClass'
action(:index)
action(:show)
action(:update)
end
It's possible to define custom max_page_size
in controller action like this:
class MyController < GraphqlRails::Controller
action(:index).paginated(max_page_size: 999)
end
sadly this does not work as promised - it still returns 200
records max
Currently there is no namespace in routes, but it would be nice to have one. For example
GraphqlRails::Router.draw do
namespace :admin do
resources :users
end
end
I would expect that this will generate something like this:
query {
admin {
users
user(...)
}
}
mutation {
admin {
createUser(...)
updateUser(...)
destroyUser(...)
}
}
All model fields are camelized and there is no way how to change this. It would be nice to have option to do so, something like this:
class User
include GraphqlRails::Model
graphql do |c|
c.attribute :underscored_name, type: :string!, name_format: :original
end
end
With automated CI, we currently lack automated/semi-automated release flow.
There's no obvious release rules or guidelines, so this needs to be discussed first.
When trying to access the total field on connection, it returns error.
My query
{
brand(id: "1") {
id
products(first: 10) {
nodes {
id
}
total
}
}
}
It si configured using
...
c.attribute(:products, type: '[Catalog::Product]').paginated
...
And it returns
Failed to implement ProductConnection.total, tried:
- `#<Class:0x00007fed248f6c40>#total`, which did not exist
- `GraphQL::Relay::RelationConnection#total`, which did not exist
- Looking up hash key `:total` or `"total"` on `#<GraphQL::Relay::RelationConnection:0x00007fed2803d7d0>`, but it wasn't a Hash
To implement this field, define one of the methods above (and check for typos)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.