graphql_rails 0.5.2 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.hound.yml +1 -0
  3. data/.rubocop.yml +3 -3
  4. data/.ruby-version +1 -1
  5. data/.travis.yml +2 -2
  6. data/CHANGELOG.md +35 -0
  7. data/Gemfile +3 -2
  8. data/Gemfile.lock +179 -71
  9. data/docs/README.md +48 -9
  10. data/docs/_sidebar.md +5 -0
  11. data/docs/components/controller.md +294 -8
  12. data/docs/components/decorator.md +69 -0
  13. data/docs/components/model.md +349 -11
  14. data/docs/components/routes.md +43 -1
  15. data/docs/getting_started/quick_start.md +9 -2
  16. data/docs/index.html +1 -1
  17. data/docs/logging_and_monitoring/logging_and_monitoring.md +35 -0
  18. data/docs/other_tools/query_runner.md +49 -0
  19. data/docs/other_tools/schema_dump.md +29 -0
  20. data/docs/testing/testing.md +3 -1
  21. data/graphql_rails.gemspec +5 -4
  22. data/lib/generators/graphql_rails/install_generator.rb +50 -0
  23. data/lib/generators/graphql_rails/templates/example_users_controller.erb +19 -0
  24. data/lib/generators/graphql_rails/templates/graphql_application_controller.erb +8 -0
  25. data/lib/generators/graphql_rails/templates/graphql_controller.erb +20 -0
  26. data/lib/generators/graphql_rails/templates/graphql_router.erb +19 -0
  27. data/lib/generators/graphql_rails/templates/graphql_router_spec.erb +21 -0
  28. data/lib/graphql_rails.rb +7 -1
  29. data/lib/graphql_rails/attributes.rb +13 -0
  30. data/lib/graphql_rails/{attribute → attributes}/attributable.rb +25 -20
  31. data/lib/graphql_rails/attributes/attribute.rb +94 -0
  32. data/lib/graphql_rails/{attribute → attributes}/attribute_name_parser.rb +2 -2
  33. data/lib/graphql_rails/attributes/input_attribute.rb +65 -0
  34. data/lib/graphql_rails/attributes/input_type_parser.rb +62 -0
  35. data/lib/graphql_rails/attributes/type_name_info.rb +38 -0
  36. data/lib/graphql_rails/attributes/type_parseable.rb +128 -0
  37. data/lib/graphql_rails/attributes/type_parser.rb +121 -0
  38. data/lib/graphql_rails/concerns/service.rb +19 -0
  39. data/lib/graphql_rails/controller.rb +44 -22
  40. data/lib/graphql_rails/controller/action.rb +12 -67
  41. data/lib/graphql_rails/controller/action_configuration.rb +71 -31
  42. data/lib/graphql_rails/controller/build_controller_action_resolver.rb +52 -0
  43. data/lib/graphql_rails/controller/build_controller_action_resolver/controller_action_resolver.rb +28 -0
  44. data/lib/graphql_rails/controller/configuration.rb +58 -4
  45. data/lib/graphql_rails/controller/log_controller_action.rb +66 -0
  46. data/lib/graphql_rails/controller/request.rb +29 -8
  47. data/lib/graphql_rails/controller/request/format_errors.rb +58 -0
  48. data/lib/graphql_rails/decorator.rb +41 -0
  49. data/lib/graphql_rails/decorator/relation_decorator.rb +79 -0
  50. data/lib/graphql_rails/errors/custom_execution_error.rb +22 -0
  51. data/lib/graphql_rails/errors/execution_error.rb +8 -7
  52. data/lib/graphql_rails/errors/system_error.rb +14 -0
  53. data/lib/graphql_rails/errors/validation_error.rb +1 -5
  54. data/lib/graphql_rails/input_configurable.rb +47 -0
  55. data/lib/graphql_rails/integrations.rb +19 -0
  56. data/lib/graphql_rails/integrations/lograge.rb +39 -0
  57. data/lib/graphql_rails/integrations/sentry.rb +34 -0
  58. data/lib/graphql_rails/model.rb +26 -4
  59. data/lib/graphql_rails/model/add_fields_to_graphql_type.rb +45 -0
  60. data/lib/graphql_rails/model/build_connection_type.rb +48 -0
  61. data/lib/graphql_rails/model/{configuration → build_connection_type}/count_items.rb +4 -4
  62. data/lib/graphql_rails/model/build_enum_type.rb +68 -0
  63. data/lib/graphql_rails/model/{graphql_input_type_builder.rb → build_graphql_input_type.rb} +10 -2
  64. data/lib/graphql_rails/model/call_graphql_model_method.rb +72 -0
  65. data/lib/graphql_rails/model/configurable.rb +6 -2
  66. data/lib/graphql_rails/model/configuration.rb +34 -19
  67. data/lib/graphql_rails/model/find_or_build_graphql_type.rb +64 -0
  68. data/lib/graphql_rails/model/find_or_build_graphql_type_class.rb +46 -0
  69. data/lib/graphql_rails/model/input.rb +25 -11
  70. data/lib/graphql_rails/query_runner.rb +68 -0
  71. data/lib/graphql_rails/railtie.rb +10 -0
  72. data/lib/graphql_rails/router.rb +40 -13
  73. data/lib/graphql_rails/router/plain_cursor_encoder.rb +16 -0
  74. data/lib/graphql_rails/router/resource_routes_builder.rb +19 -11
  75. data/lib/graphql_rails/router/route.rb +21 -6
  76. data/lib/graphql_rails/router/schema_builder.rb +29 -11
  77. data/lib/graphql_rails/rspec_controller_helpers.rb +25 -12
  78. data/lib/graphql_rails/tasks/dump_graphql_schema.rb +57 -0
  79. data/lib/graphql_rails/tasks/schema.rake +14 -0
  80. data/lib/graphql_rails/version.rb +1 -1
  81. metadata +75 -22
  82. data/README.md +0 -194
  83. data/lib/graphql_rails/attribute.rb +0 -28
  84. data/lib/graphql_rails/attribute/type_parser.rb +0 -115
  85. data/lib/graphql_rails/controller/controller_function.rb +0 -50
  86. data/lib/graphql_rails/controller/format_results.rb +0 -36
  87. data/lib/graphql_rails/model/graphql_type_builder.rb +0 -33
  88. data/lib/graphql_rails/model/input_attribute.rb +0 -47
data/README.md DELETED
@@ -1,194 +0,0 @@
1
- # GraphqlRails
2
-
3
- [![Build Status](https://travis-ci.org/samesystem/graphql_rails.svg?branch=master)](https://travis-ci.org/samesystem/graphql_rails)
4
- [![codecov](https://codecov.io/gh/samesystem/graphql_rails/branch/master/graph/badge.svg)](https://codecov.io/gh/samesystem/graphql_rails)
5
- [![Documentation](https://readthedocs.org/projects/ansicolortags/badge/?version=latest)](https://samesystem.github.io/graphql_rails)
6
-
7
- Rails style structure for GraphQL API.
8
-
9
- ## Installation
10
-
11
- Add this line to your application's Gemfile:
12
-
13
- ```ruby
14
- gem 'graphql_rails'
15
- ```
16
-
17
- And then execute:
18
-
19
- $ bundle
20
-
21
- Or install it yourself as:
22
-
23
- $ gem install graphql_rails
24
-
25
- ## Usage
26
-
27
- ### Define GraphQL schema as RoR routes
28
-
29
- ```ruby
30
- MyGraphqlSchema = GraphqlRails::Router.draw do
31
- # will create createUser, updateUser, deleteUser mutations and user, users queries.
32
- # expects that UsersController class exist
33
- resources :users
34
-
35
- # if you want custom queries or mutation
36
- query 'searchLogs', to: 'logs#search' # redirects request to LogsController
37
- mutation 'changeUserPassword', to: 'users#change_password'
38
- end
39
- ```
40
-
41
- ### Define your Graphql model
42
-
43
- ```ruby
44
- class User # works with any class including ActiveRecord
45
- include GraphqlRails::Model
46
-
47
- graphql do |c|
48
- # most common attributes, like :id, :name, :title has default type, so you don't have to specify it (but you can!)
49
- c.attribute :id
50
-
51
- c.attribute :email, type: :string
52
- c.attribute :surname, type: :string
53
- end
54
- end
55
- ```
56
-
57
- ### Define controller
58
-
59
- ```ruby
60
- class UsersController < GraphqlRails::Controller
61
- # graphql requires to describe which attributes controller action accepts and which returns
62
- action(:change_user_password)
63
- .permit(:password!, :id!) # Bang (!) indicates that attribute is required
64
-
65
- def change_user_password
66
- user = User.find(params[:id])
67
- user.update!(password: params[:password])
68
-
69
- # returned value needs to have all methods defined in model `graphql do` part
70
- user # or SomeDecorator.new(user)
71
- end
72
-
73
- action(:search).permit(search_fields!: SearchFieldsInput) # you can specify your own input fields
74
- def search
75
- end
76
- end
77
- ```
78
-
79
- ## Routes
80
-
81
- ```ruby
82
- MyGraphqlSchema = GraphqlRails::Router.draw do
83
- # generates `friend`, `createFriend`, `updateFriend`, `destroyFriend`, `friends` routes
84
- resources :friends
85
- resources :shops, only: [:show, :index] # generates `shop` and `shops` routes only
86
- resources :orders, except: :update # generates all routes except `updateOrder`
87
-
88
- resources :users do
89
- # generates `findUser` query
90
- query :find, on: :member
91
-
92
- # generates `searchUsers` query
93
- query :search, on: :collection
94
- end
95
-
96
- # you can use namespaced controllers too:
97
- scope module: 'admin' do
98
- # `updateTranslations` route will be handeled by `Admin::TranslationsController`
99
- mutation :updateTranslations, to: 'translations#update'
100
-
101
- # all :groups routes will be handeled by `Admin::GroupsController`
102
- resources :groups
103
- end
104
- end
105
- ```
106
-
107
- ## Testing your GraphqlRails::Controller in RSpec
108
-
109
- ### Setup
110
-
111
- Add those lines in your `spec/spec_helper.rb` file
112
-
113
- ```ruby
114
- # spec/spec_helper.rb
115
- require 'graphql_rails/rspec_controller_helpers'
116
-
117
- RSpec.configure do |config|
118
- config.include(GraphqlRails::RSpecControllerHelpers, type: :graphql_controller)
119
- # ... your other configuration ...
120
- end
121
- ```
122
-
123
- ### Helper methods
124
-
125
- There are 3 helper methods:
126
-
127
- * `mutation(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
128
- * `query(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
129
- * `response`. Response is set only after you call `mutation` or `query`
130
-
131
- ### Test examples
132
-
133
- ```ruby
134
- class MyGraphqlController
135
- def index
136
- "Called from index: #{params[:message]}"
137
- end
138
-
139
- action(:create_user).permit(:full_name, :email)
140
- def create_user
141
- User.create!(params)
142
- end
143
- end
144
-
145
- RSpec.describe MyGraphqlController, type: :graphql_controller do
146
- describe '#index' do
147
- it 'is successful' do
148
- query(:index)
149
- expect(response).to be_successful
150
- end
151
-
152
- it 'returns correct message' do
153
- query(:index, params: { message: 'Hello world!' })
154
- expect(response.result).to eq "Called from index: Hello world!"
155
- end
156
- end
157
-
158
- describe '#create_user' do
159
- context 'when bad email is given' do
160
- it 'fails' do
161
- mutation(:create_user, params { email: 'bad' })
162
- expect(response).to be_failure
163
- end
164
-
165
- it 'contains errors' do
166
- mutation(:create_user, params { email: 'bad' })
167
- expect(response.errors).not_to be_empty
168
- end
169
- end
170
- end
171
- end
172
- ```
173
-
174
- ## Detailed documentation
175
-
176
- Check https://samesystem.github.io/graphql_rails for more details
177
-
178
- ## Development
179
-
180
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
181
-
182
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
183
-
184
- ## Contributing
185
-
186
- Bug reports and pull requests are welcome on GitHub at https://github.com/samesystem/graphql_rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
187
-
188
- ## License
189
-
190
- The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
191
-
192
- ## Code of Conduct
193
-
194
- Everyone interacting in the GraphqlRails project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/samesystem/graphql_rails/blob/master/CODE_OF_CONDUCT.md).
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'graphql'
4
- require 'graphql_rails/attribute/attributable'
5
-
6
- module GraphqlRails
7
- # contains info about single graphql attribute
8
- class Attribute
9
- include Attributable
10
-
11
- attr_reader :property, :description
12
-
13
- def initialize(name, type = nil, description: nil, property: name)
14
- @initial_type = type
15
- @initial_name = name
16
- @description = description
17
- @property = property.to_s
18
- end
19
-
20
- def field_args
21
- [field_name, graphql_field_type, { property: property.to_sym, description: description }]
22
- end
23
-
24
- protected
25
-
26
- attr_reader :initial_type, :initial_name
27
- end
28
- end
@@ -1,115 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'graphql'
4
-
5
- module GraphqlRails
6
- class Attribute
7
- # converts string value in to GraphQL type
8
- class TypeParser
9
- class UnknownTypeError < ArgumentError; end
10
-
11
- TYPE_MAPPING = {
12
- 'id' => GraphQL::ID_TYPE,
13
-
14
- 'int' => GraphQL::INT_TYPE,
15
- 'integer' => GraphQL::INT_TYPE,
16
-
17
- 'string' => GraphQL::STRING_TYPE,
18
- 'str' => GraphQL::STRING_TYPE,
19
- 'text' => GraphQL::STRING_TYPE,
20
- 'time' => GraphQL::STRING_TYPE,
21
- 'date' => GraphQL::STRING_TYPE,
22
-
23
- 'bool' => GraphQL::BOOLEAN_TYPE,
24
- 'boolean' => GraphQL::BOOLEAN_TYPE,
25
-
26
- 'float' => GraphQL::FLOAT_TYPE,
27
- 'double' => GraphQL::FLOAT_TYPE,
28
- 'decimal' => GraphQL::FLOAT_TYPE
29
- }.freeze
30
-
31
- def initialize(unparsed_type)
32
- @unparsed_type = unparsed_type
33
- end
34
-
35
- def graphql_type
36
- return unparsed_type if raw_graphql_type?
37
-
38
- if list?
39
- parsed_list_type
40
- else
41
- parsed_inner_type
42
- end
43
- end
44
-
45
- def graphql_model
46
- type_class = inner_type_name.safe_constantize
47
- return unless type_class.respond_to?(:graphql)
48
-
49
- type_class
50
- end
51
-
52
- private
53
-
54
- attr_reader :unparsed_type
55
-
56
- def parsed_list_type
57
- list_type = parsed_inner_type.to_list_type
58
-
59
- if required_list_type?
60
- list_type.to_non_null_type
61
- else
62
- list_type
63
- end
64
- end
65
-
66
- def parsed_inner_type
67
- if required_inner_type?
68
- type_by_name.to_non_null_type
69
- else
70
- type_by_name
71
- end
72
- end
73
-
74
- def required_inner_type?
75
- !!unparsed_type[/\w!/] # rubocop:disable Style/DoubleNegation
76
- end
77
-
78
- def list?
79
- unparsed_type.to_s.include?(']')
80
- end
81
-
82
- def required_list_type?
83
- unparsed_type.to_s.include?(']!')
84
- end
85
-
86
- def raw_graphql_type?
87
- unparsed_type.is_a?(GraphQL::BaseType) ||
88
- unparsed_type.is_a?(GraphQL::ObjectType) ||
89
- unparsed_type.is_a?(GraphQL::InputObjectType) ||
90
- (defined?(GraphQL::Schema::Member) && unparsed_type.is_a?(Class) && unparsed_type < GraphQL::Schema::Member)
91
- end
92
-
93
- def inner_type_name
94
- unparsed_type.to_s.tr('[]!', '')
95
- end
96
-
97
- def type_by_name
98
- TYPE_MAPPING.fetch(inner_type_name.downcase) do
99
- dynamicly_defined_type || raise(
100
- UnknownTypeError,
101
- "Type #{unparsed_type.inspect} is not supported. Supported scalar types are: #{TYPE_MAPPING.keys}." \
102
- ' All the classes that includes `GraphqlRails::Model` are also supported as types.'
103
- )
104
- end
105
- end
106
-
107
- def dynamicly_defined_type
108
- type_class = graphql_model
109
- return unless type_class
110
-
111
- type_class.graphql.graphql_type
112
- end
113
- end
114
- end
115
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'graphql_rails/controller/action'
4
- require_relative 'request'
5
- require_relative 'action'
6
-
7
- module GraphqlRails
8
- class Controller
9
- # graphql resolver which redirects actions to appropriate controller and controller action
10
- class ControllerFunction < GraphQL::Function
11
- # accepts path of given format "controller_name#action"
12
- attr_reader :type
13
-
14
- def initialize(controller:, action_name:, type:)
15
- @controller = controller
16
- @action_name = action_name
17
- @type = type
18
- end
19
-
20
- def self.from_route(route)
21
- action = Action.new(route)
22
-
23
- action_function_class(action).new(
24
- controller: action.controller,
25
- action_name: action.name,
26
- type: action.return_type
27
- )
28
- end
29
-
30
- def self.action_function_class(action)
31
- Class.new(self) do
32
- description(action.description)
33
-
34
- action.arguments.each do |attribute|
35
- argument(*attribute.function_argument_args)
36
- end
37
- end
38
- end
39
-
40
- def call(object, inputs, ctx)
41
- request = Request.new(object, inputs, ctx)
42
- controller.new(request).call(action_name)
43
- end
44
-
45
- private
46
-
47
- attr_reader :controller, :action_name
48
- end
49
- end
50
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphqlRails
4
- class Controller
5
- # Convers raw controller results in to graphql-friendly format
6
- class FormatResults
7
- def initialize(original_result, action_config:, params:, graphql_context:)
8
- @original_result = original_result
9
- @action_config = action_config
10
- @controller_params = params
11
- @graphql_context = graphql_context
12
- end
13
-
14
- def call
15
- if action_config.paginated? && original_result
16
- paginated_result
17
- else
18
- original_result
19
- end
20
- end
21
-
22
- private
23
-
24
- attr_reader :original_result, :action_config, :controller_params, :graphql_context
25
-
26
- def paginated_result
27
- pagination_params = controller_params.slice(:first, :last, :before, :after)
28
- pagination_options = action_config.pagination_options.merge(context: graphql_context)
29
-
30
- GraphQL::Relay::BaseConnection
31
- .connection_for_nodes(original_result)
32
- .new(original_result, pagination_params, pagination_options)
33
- end
34
- end
35
- end
36
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module GraphqlRails
4
- module Model
5
- # stores information about model specific config, like attributes and types
6
- class GraphqlTypeBuilder
7
- def initialize(name:, description: nil, attributes:)
8
- @name = name
9
- @attributes = attributes
10
- @description = description
11
- end
12
-
13
- def call
14
- type_name = name
15
- type_description = description
16
- type_attributes = attributes
17
-
18
- GraphQL::ObjectType.define do
19
- name(type_name)
20
- description(type_description)
21
-
22
- type_attributes.each_value do |attribute|
23
- field(*attribute.field_args)
24
- end
25
- end
26
- end
27
-
28
- private
29
-
30
- attr_reader :model_configuration, :attributes, :name, :description
31
- end
32
- end
33
- end