graphql_model_mapper 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +8 -0
- data/.travis.yml +5 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +45 -0
- data/LICENSE.txt +21 -0
- data/README.md +416 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/graphql_model_mapper.gemspec +37 -0
- data/lib/graphql_model_mapper/mapper_type.rb +340 -0
- data/lib/graphql_model_mapper/mutation.rb +125 -0
- data/lib/graphql_model_mapper/query.rb +107 -0
- data/lib/graphql_model_mapper/railtie.rb +8 -0
- data/lib/graphql_model_mapper/resolve.rb +221 -0
- data/lib/graphql_model_mapper/schema.rb +110 -0
- data/lib/graphql_model_mapper/schema_types.rb +0 -0
- data/lib/graphql_model_mapper/utility.rb +0 -0
- data/lib/graphql_model_mapper/version.rb +3 -0
- data/lib/graphql_model_mapper.rb +228 -0
- metadata +122 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c4b6b09863ce496e54d98306ed8edc1a31e720d1
|
4
|
+
data.tar.gz: c00f8470a348752631c91c280715f4f8cb59fe0e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a7a0e7b631352b9314c28ef35ae3bddf89cffa2ab9c82c76e219a033396945c97f59ab42091185007ab23b152d2f8a312b383d09b783b3838757637f4a4749f0
|
7
|
+
data.tar.gz: d3b1c83e2b307b86e47707c140efba01e461b13c8e25d4497b64b89c39875a3875f21c04f0d456390cca2fa3b6f14f7ef9d09da7ae4012c3cbbb8737913bc3f2
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
gem 'rake'
|
4
|
+
gem 'activerecord', '~>3.2.22.5', :require => 'active_record'
|
5
|
+
gem 'activemodel', '~>3.2.22.5', :require => 'active_record'
|
6
|
+
gem 'activesupport', '~>3.2.22.5', :require => 'active_support'
|
7
|
+
gem 'graphql', '~>1.7.5'
|
8
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
9
|
+
|
10
|
+
# Specify your gem's dependencies in graphql_model_mapper.gemspec
|
11
|
+
gemspec
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
graphql_model_mapper (0.0.2)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
activemodel (3.2.22.5)
|
10
|
+
activesupport (= 3.2.22.5)
|
11
|
+
builder (~> 3.0.0)
|
12
|
+
activerecord (3.2.22.5)
|
13
|
+
activemodel (= 3.2.22.5)
|
14
|
+
activesupport (= 3.2.22.5)
|
15
|
+
arel (~> 3.0.2)
|
16
|
+
tzinfo (~> 0.3.29)
|
17
|
+
activesupport (3.2.22.5)
|
18
|
+
i18n (~> 0.6, >= 0.6.4)
|
19
|
+
multi_json (~> 1.0)
|
20
|
+
arel (3.0.3)
|
21
|
+
builder (3.0.4)
|
22
|
+
concurrent-ruby (1.0.5)
|
23
|
+
graphql (1.7.5)
|
24
|
+
i18n (0.9.1)
|
25
|
+
concurrent-ruby (~> 1.0)
|
26
|
+
minitest (5.10.3)
|
27
|
+
multi_json (1.12.2)
|
28
|
+
rake (12.2.1)
|
29
|
+
tzinfo (0.3.53)
|
30
|
+
|
31
|
+
PLATFORMS
|
32
|
+
ruby
|
33
|
+
|
34
|
+
DEPENDENCIES
|
35
|
+
activemodel (~> 3.2.22.5)
|
36
|
+
activerecord (~> 3.2.22.5)
|
37
|
+
activesupport (~> 3.2.22.5)
|
38
|
+
bundler (~> 1.16)
|
39
|
+
graphql (~> 1.7.5)
|
40
|
+
graphql_model_mapper!
|
41
|
+
minitest (~> 5.0)
|
42
|
+
rake
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
1.16.0
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 Gene Black
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,416 @@
|
|
1
|
+
# graphql_model_mapper
|
2
|
+
This project is a work in progress and is in a pre-alpha state. Many thanks to @AndyKriger https://github.com/AndyKriger who initiated and shared the original idea on the GraphQL issue thread https://github.com/rmosolgo/graphql-ruby/issues/945.
|
3
|
+
|
4
|
+
The graphql_model_mapper gem facilitates the generation of GraphQL objects based on the definition of your existing ActiveRecord models.
|
5
|
+
|
6
|
+
It has been tested on Rails 3.2, 4.1 and 5.0 using Ruby 2.2.8
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'graphql_model_mapper', :git => "git://github.com/geneeblack/graphql_model_mapper.git"
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install graphql_model_mapper
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
Initially, you will not have any models exposed as GraphQL types. To expose a model you can add any/all of the following macro attributes to your model definition:
|
27
|
+
|
28
|
+
graphql_query # to generate a GraphQL query object (and associated GraphQL input/output types) for the model
|
29
|
+
graphql_create # to generate a GraphQL create mutation object (and its associated GraphQL input/output types) for the model
|
30
|
+
graphql_delete # to generate a GraphQL delete mutation object (and its associated GraphQL input/output types) for the model
|
31
|
+
graphql_update # to generate a GraphQL update mutation object (and its associated GraphQL input/output types) for the model
|
32
|
+
|
33
|
+
The default input/output types generated for the model are based on the default settings (which may be overriden by initializing GraphqlModelMapper::GRAPHQL_DEFAULT_TYPES in your own initializer
|
34
|
+
|
35
|
+
Note that the query and delete mutations do not have an input type defined since their arguments are currently generated internally:
|
36
|
+
|
37
|
+
GraphqlModelMapper::GRAPHQL_DEFAULT_TYPES =
|
38
|
+
query: {
|
39
|
+
output_type: {
|
40
|
+
required_attributes: [], # attributes required in the type - empty list defaults to no required attributes
|
41
|
+
excluded_attributes: [], # exclude these attributes from the type - empty list defaults to no excluded attributes
|
42
|
+
allowed_attributes: [], # only allow these attributes in the type - empty list defaults to all attributes allowed
|
43
|
+
foreign_keys: true, # generate the foreign keys on the type
|
44
|
+
primary_keys: true, # generate the primary keys for the type
|
45
|
+
validation_keys: false, # generate non-nullable validation keys for the type
|
46
|
+
association_macro: nil, # generate the associations fo the type - nil defaults to all associations (other than those that are polymorphic), you may also specify :has_many or :belongs_to or :has_one
|
47
|
+
source_nulls: false, # use the null definitions that are defined by the database for the exposed attributes
|
48
|
+
type_key: :query, # internal identifier for the query/mutation type for which this type definition applies
|
49
|
+
type_sub_key: :output_type # internal sub-identifier for the input/output type for which this definition applies
|
50
|
+
}
|
51
|
+
},
|
52
|
+
update: {
|
53
|
+
input_type: {
|
54
|
+
required_attributes: [],
|
55
|
+
excluded_attributes: [],
|
56
|
+
allowed_attributes: [],
|
57
|
+
foreign_keys: true,
|
58
|
+
primary_keys: true,
|
59
|
+
validation_keys: false,
|
60
|
+
association_macro: nil,
|
61
|
+
source_nulls: false,
|
62
|
+
type_key: :update,
|
63
|
+
type_sub_key: :input_type
|
64
|
+
},
|
65
|
+
output_type: {
|
66
|
+
required_attributes: [],
|
67
|
+
excluded_attributes: [],
|
68
|
+
allowed_attributes: [],
|
69
|
+
foreign_keys: true,
|
70
|
+
primary_keys: true,
|
71
|
+
validation_keys: false,
|
72
|
+
association_macro: nil,
|
73
|
+
source_nulls: true,
|
74
|
+
type_key: :update,
|
75
|
+
type_sub_key: :output_type
|
76
|
+
}
|
77
|
+
},
|
78
|
+
delete: {
|
79
|
+
output_type: {
|
80
|
+
required_attributes: [],
|
81
|
+
excluded_attributes: [],
|
82
|
+
allowed_attributes: [],
|
83
|
+
foreign_keys: false,
|
84
|
+
primary_keys: true,
|
85
|
+
validation_keys: false,
|
86
|
+
association_macro: nil,
|
87
|
+
source_nulls: true,
|
88
|
+
type_key: :delete,
|
89
|
+
type_sub_key: :output_type
|
90
|
+
}
|
91
|
+
},
|
92
|
+
create: {
|
93
|
+
input_type: {
|
94
|
+
required_attributes: [],
|
95
|
+
excluded_attributes: [],
|
96
|
+
allowed_attributes: [],
|
97
|
+
foreign_keys: true,
|
98
|
+
primary_keys: false,
|
99
|
+
validation_keys: false,
|
100
|
+
association_macro: :has_many,
|
101
|
+
source_nulls: false,
|
102
|
+
type_key: :create,
|
103
|
+
type_sub_key: :input_type
|
104
|
+
},
|
105
|
+
output_type: {
|
106
|
+
required_attributes: [],
|
107
|
+
excluded_attributes: [],
|
108
|
+
allowed_attributes: [],
|
109
|
+
foreign_keys: true,
|
110
|
+
primary_keys: true,
|
111
|
+
validation_keys: false,
|
112
|
+
association_macro: nil,
|
113
|
+
source_nulls: true,
|
114
|
+
type_key: :create,
|
115
|
+
type_sub_key: :output_type
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
or individually by using the
|
120
|
+
|
121
|
+
graphql_type
|
122
|
+
|
123
|
+
macro attribute on the model, passing the individual settings that differ from the defaults. i.e.
|
124
|
+
|
125
|
+
|
126
|
+
graphql_types query: {
|
127
|
+
output_type: {
|
128
|
+
excluded_attributes: [:crypted_password]
|
129
|
+
}
|
130
|
+
},
|
131
|
+
update: {
|
132
|
+
input_type: {
|
133
|
+
excluded_attributes: [:crypted_password]
|
134
|
+
},
|
135
|
+
output_type: {
|
136
|
+
excluded_attributes: [:crypted_password]
|
137
|
+
}
|
138
|
+
},
|
139
|
+
create: {
|
140
|
+
input_type: {
|
141
|
+
excluded_attributes: [:crypted_password]
|
142
|
+
},
|
143
|
+
output_type: {
|
144
|
+
excluded_attributes: [:crypted_password]
|
145
|
+
}
|
146
|
+
},
|
147
|
+
delete: {
|
148
|
+
input_type: {
|
149
|
+
excluded_attributes: [:crypted_password]
|
150
|
+
},
|
151
|
+
output_type: {
|
152
|
+
excluded_attributes: [:crypted_password]
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
## Other Options
|
157
|
+
|
158
|
+
The query and mutation objects have a default resolver defined that may be sufficient for your needs (with the exception of the create mutation which most likely will not be adequate for your implementation, currently it simply validates the input and does not attempt to add the record).
|
159
|
+
|
160
|
+
def self.create_resolver(obj, inputs, ctx, model_name)
|
161
|
+
if !GraphqlModelMapper.authorized?(ctx, model_name, :create)
|
162
|
+
raise GraphQL::ExecutionError.new("error: unauthorized access: create '#{model_name.classify}'")
|
163
|
+
end
|
164
|
+
model = model_name.classify.constantize
|
165
|
+
item = model.new(inputs[model_name.downcase].to_h)
|
166
|
+
begin
|
167
|
+
if !item.valid?
|
168
|
+
raise GraphQL::ExecutionError.new(item.errors.full_messages.join("; "))
|
169
|
+
else
|
170
|
+
raise GraphQL::ExecutionError.new("error: WIP, item not saved but is a valid '#{model_name.classify}'")
|
171
|
+
#item.save!
|
172
|
+
end
|
173
|
+
end
|
174
|
+
item
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
If you want to assign your own resolvers for your type you can override the default resolver for the type on the macro attribute in the following way:
|
179
|
+
|
180
|
+
graphql_query resolver: -> (obj, inputs, ctx){ raise GraphQL::ExecutionError.new(inputs.to_h.to_a) }
|
181
|
+
|
182
|
+
The method that you assign to the resolver should either be self contained or call a class method that accepts and orchestrates the parameters passed from GraphQL in the resolve. In this example it is simply calling a GraphQL::ExecutionError to output the contents of the input parameters. These methods could be anywhere in your application, they are not limited to the model on which they are defined.
|
183
|
+
|
184
|
+
When returning items to populate the appropriate output type, return them as a hash value shaped to fit the output types definition. GraphQL will take care of the final mapping and shapping of the models item(s)
|
185
|
+
|
186
|
+
resolver: -> (obj, inputs, ctx){
|
187
|
+
items = YourClass.method_that_returns_items(obj, inputs, ctx, name)
|
188
|
+
{
|
189
|
+
total: items.length,
|
190
|
+
items: items
|
191
|
+
}
|
192
|
+
}
|
193
|
+
or
|
194
|
+
|
195
|
+
resolver: -> (obj, inputs, ctx){
|
196
|
+
items = YourClass.method_that_returns_an_item(obj, inputs, ctx, name)
|
197
|
+
{
|
198
|
+
item: item
|
199
|
+
}
|
200
|
+
}
|
201
|
+
|
202
|
+
|
203
|
+
Some other attributes that you can set on the graphql_query in addition to the resolver are
|
204
|
+
|
205
|
+
## graphql_query
|
206
|
+
|
207
|
+
description: # a short description of the query
|
208
|
+
scope_methods: # scope methods available to be used in the query, these should not be parameterized and must be written so that they do not collide with other tables which may be included in the associations
|
209
|
+
arguments: # a list of argument definitions to override the default arguments, if using your own arguments you will need to override the query resolver to act on those arguments, the default arguments exposed on the query are:
|
210
|
+
|
211
|
+
default_arguments =
|
212
|
+
[{:name=>:explain, :type=>GraphQL::BOOLEAN_TYPE, :default=>nil}, # handled by the default resolver, outputs the top level sql for the operation
|
213
|
+
{:name=>:id, :type=>GraphQL::INT_TYPE, :default=>nil}, # allows input of an id for top level record selection for the model
|
214
|
+
{:name=>:ids, :type=>GraphQL::INT_TYPE.to_list_type, :default=>nil}, # allows input of an array of ids for top level records selection for the model
|
215
|
+
{:name=>:limit, :type=>GraphQL::INT_TYPE, :default=>50}, # limits the number of records retuurned (defaults to 50 records)
|
216
|
+
{:name=>:offset, :type=>GraphQL::INT_TYPE, :default=>nil}, # specifies an offset for the start of the records returned
|
217
|
+
{:name=>:order, :type=>GraphQL::STRING_TYPE, :default=>nil}, # a string value that is passed to ActiveRecord query specifying the output order
|
218
|
+
{:name=>:where, :type=>GraphQL::STRING_TYPE.to_list_type, :default=>nil}] # a string array for use in ActiveRecord query, can be a string or a query/value array to be used by the query ["model.id =? and model.date is not nul]", "1"]
|
219
|
+
|
220
|
+
## graphql_delete
|
221
|
+
description:
|
222
|
+
scope_methods:
|
223
|
+
arguments:
|
224
|
+
resolver:
|
225
|
+
|
226
|
+
## graphql_update
|
227
|
+
|
228
|
+
description:
|
229
|
+
resolver:
|
230
|
+
|
231
|
+
## graphql_create
|
232
|
+
|
233
|
+
description:
|
234
|
+
resolver:
|
235
|
+
|
236
|
+
|
237
|
+
## Optional Authorization
|
238
|
+
|
239
|
+
The schema has the capability to use the cancancan gem to enable authorized access to the query and mutation fields based on the models, if implemented it also will control the availability of the associations assigned to the model based on their underlying model authorization. This is an optional setup and is not required.
|
240
|
+
|
241
|
+
gem "cancancan", "~> 1.10"
|
242
|
+
|
243
|
+
Follow the setup for cancancan and create an app/model/ability.rb file to setup your access rights
|
244
|
+
|
245
|
+
class Ability
|
246
|
+
include CanCan::Ability
|
247
|
+
|
248
|
+
def initialize(user)
|
249
|
+
# Define abilities for the passed in user here. For example:
|
250
|
+
#
|
251
|
+
# user ||= User.new # guest user (not logged in)
|
252
|
+
# if user.admin?
|
253
|
+
# can :manage, :all
|
254
|
+
# else
|
255
|
+
# can :read, :all
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# The first argument to `can` is the action you are giving the user
|
259
|
+
# permission to do.
|
260
|
+
# If you pass :manage it will apply to every action. Other common actions
|
261
|
+
# here are :read, :create, :update and :destroy.
|
262
|
+
#
|
263
|
+
# The second argument is the resource the user can perform the action on.
|
264
|
+
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
|
265
|
+
# class of the resource.
|
266
|
+
#
|
267
|
+
# The third argument is an optional hash of conditions to further filter the
|
268
|
+
# objects.
|
269
|
+
# For example, here the user can only update published articles.
|
270
|
+
#
|
271
|
+
# can :update, Article, :published => true
|
272
|
+
#
|
273
|
+
# See the wiki for details:
|
274
|
+
# https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities
|
275
|
+
|
276
|
+
|
277
|
+
user ||= User.new # guest user (not logged in)
|
278
|
+
if user.is_admin?
|
279
|
+
can :manage, :all
|
280
|
+
else
|
281
|
+
can :manage, [YourModelA] # this will allow access to :query, :create, :update, :delete GraphQL methods for defined models
|
282
|
+
can :read, [YourModelB] # this will allow access to :query GraphQL methods for defined models as well as allow read access to associations of that type
|
283
|
+
can :create, [YourModelC] # this will allow access to :create GraphQL methods for defined models
|
284
|
+
can :update, [YourModelD] # this will allow access to :update GraphQL methods for defined models
|
285
|
+
can :delete, [YourModelE] # this will allow access to :delete GraphQL methods for defined models
|
286
|
+
|
287
|
+
end
|
288
|
+
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
|
293
|
+
GraphqlModelMapper requires an optional ability method on your current_user in order to check the context current_users authorization to access a GraphQL objects model implementation.
|
294
|
+
|
295
|
+
class User < ActiveRecord::Base
|
296
|
+
def ability
|
297
|
+
@ability ||= Ability.new(self)
|
298
|
+
end
|
299
|
+
|
300
|
+
...
|
301
|
+
end
|
302
|
+
|
303
|
+
## Schema implementation
|
304
|
+
|
305
|
+
Once you have your models decorated with the graphql_query/graphql_update/graphql_create/graphql_delete attributes the next step is implementing your schema and adding it to your controller. For this example I am using a schema definition located at app/graphql/graphql_model_mapper_schema.rb. I have used https://github.com/exAspArk/graphql-errors to handle errors generated from the resolve methods. It is not required but it provides an easy way to setup error handling.
|
306
|
+
|
307
|
+
#app/graphql/graphql_model_mapper_schema.rb
|
308
|
+
require 'graphql_model_mapper'
|
309
|
+
|
310
|
+
# these are options that can be passed to the schema initiation to enable query logging or for authorization setup
|
311
|
+
# nesting_strategy can be :flat, :shallow or :deep
|
312
|
+
# type_case can be :camelize, :underscore or :classify
|
313
|
+
# the default values are shown below
|
314
|
+
options = {:log_query_depth=>false, :log_query_complexity=>false, :use_backtrace=>false, :use_authorize=>false, :nesting_strategy=>:shallow, :type_case=>:camelize}
|
315
|
+
GraphqlModelMapperSchema = GraphqlModelMapper.Schema(use_authorize: true)
|
316
|
+
GraphQL::Errors.configure(GraphqlModelMapperSchema) do
|
317
|
+
|
318
|
+
rescue_from ActiveRecord::StatementInvalid do |exception|
|
319
|
+
GraphQL::ExecutionError.new(exception.message)
|
320
|
+
end
|
321
|
+
|
322
|
+
rescue_from ActiveRecord::RecordNotFound do |exception|
|
323
|
+
GraphQL::ExecutionError.new(exception.message)
|
324
|
+
end
|
325
|
+
|
326
|
+
|
327
|
+
rescue_from ActiveRecord::RecordInvalid do |exception|
|
328
|
+
GraphQL::ExecutionError.new(exception.message)
|
329
|
+
end
|
330
|
+
|
331
|
+
rescue_from StandardError do |exception|
|
332
|
+
GraphQL::ExecutionError.new(exception.message)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
## Graphiql controller setup
|
337
|
+
|
338
|
+
I recommend that you install
|
339
|
+
|
340
|
+
gem "graphiql-rails"
|
341
|
+
|
342
|
+
so you may access and test your GraphQL queries. It is located at https://github.com/rmosolgo/graphiql-rails. Once you have graphiql-rails you can setup the route
|
343
|
+
|
344
|
+
#config/routes.rb
|
345
|
+
[YourApp]::Application.routes.draw do
|
346
|
+
if Rails.env.development? || Rails.env.staging? # you can restrict access to graphiql to specific environments here
|
347
|
+
mount GraphiQL::Rails::Engine, at: "/graphiql", graphql_path: "/graphql"
|
348
|
+
end
|
349
|
+
|
350
|
+
post "/graphql", to: "graphql#execute"
|
351
|
+
|
352
|
+
....
|
353
|
+
end
|
354
|
+
|
355
|
+
you can then reference your previously assigned schema in app/controllers/graphql_contoller.rb
|
356
|
+
|
357
|
+
#app/controllers/graphql_controller
|
358
|
+
class GraphqlController < ApplicationController
|
359
|
+
def execute
|
360
|
+
variables = ensure_hash(params[:variables])
|
361
|
+
query = params[:query]
|
362
|
+
operation_name = params[:operationName]
|
363
|
+
context = {
|
364
|
+
# Query context goes here, for example:
|
365
|
+
current_user: current_user
|
366
|
+
}
|
367
|
+
|
368
|
+
begin
|
369
|
+
if (logged_in?)# && current_user.is_admin?)
|
370
|
+
Ability.new(current_user) if GraphqlModelMapper.use_authorize # set on GraphqlModelMapper.Schema initialization
|
371
|
+
elsif Rails.env != "development"
|
372
|
+
query = nil
|
373
|
+
end
|
374
|
+
result = GraphqlModelMapperSchema.execute(query, variables: variables, context: context, operation_name: operation_name, except: ExceptFilter)
|
375
|
+
|
376
|
+
end
|
377
|
+
render json: result
|
378
|
+
end
|
379
|
+
|
380
|
+
private
|
381
|
+
# this class is exercised when use_authorize is true
|
382
|
+
class ExceptFilter
|
383
|
+
def self.call(schema_member, context)
|
384
|
+
return false unless GraphqlModelMapper.use_authorize
|
385
|
+
# true if field should be excluded, false if it should be included
|
386
|
+
return false unless authorized_proc = schema_member.metadata[:authorized_proc]
|
387
|
+
model_name = schema_member.metadata[:model_name]
|
388
|
+
access_type = schema_member.metadata[:access_type]
|
389
|
+
!authorized_proc.call(context, model_name, access_type)
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
def ensure_hash(query_variables)
|
394
|
+
if query_variables.blank?
|
395
|
+
{}
|
396
|
+
elsif query_variables.is_a?(String)
|
397
|
+
JSON.parse(query_variables)
|
398
|
+
else
|
399
|
+
query_variables
|
400
|
+
end
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
## Development
|
405
|
+
|
406
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
407
|
+
|
408
|
+
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).
|
409
|
+
|
410
|
+
## Contributing
|
411
|
+
|
412
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/geneeblack/graphql_model_mapper.
|
413
|
+
|
414
|
+
## License
|
415
|
+
|
416
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "graphql_model_mapper"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "graphql_model_mapper/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "graphql_model_mapper"
|
8
|
+
spec.version = GraphqlModelMapper::VERSION
|
9
|
+
spec.authors = ["Gene Black"]
|
10
|
+
spec.email = ["geblack@hotmail.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Adds GraphQL object generation based on your ActiveRecord models.}
|
13
|
+
spec.description = %q{This gem extends ActiveRecord::Base to add automatic generation of GraphQL objects based on your models.}
|
14
|
+
spec.homepage = "https://github.com/geneblack/graphql_model_mapper"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
+
if spec.respond_to?(:metadata)
|
20
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
21
|
+
else
|
22
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
23
|
+
"public gem pushes."
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
f.match(%r{^(test|spec|features)/})
|
28
|
+
end
|
29
|
+
spec.bindir = "exe"
|
30
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
31
|
+
spec.require_paths = ["lib"]
|
32
|
+
|
33
|
+
spec.add_development_dependency "graphql", "~> 1.7.5"
|
34
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
35
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
36
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
37
|
+
end
|