graphql_rails 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6960308081875563c429085033503f5f6eb4f5078eb610c0a96e95edb4879e6f
4
- data.tar.gz: 84b19c7d4811f988ba4caf14eee6f3beb04b460ed92fc39b2d428ef219b44d38
3
+ metadata.gz: e2bd0f0c9f6aaa1808567914c7a1440302a8b7dc828e97937a264dc33cbdd0d5
4
+ data.tar.gz: eac8327fdf61cbd8bedb9301f261448a48ebeaf0d14ce78a6fd986d5aa752eb9
5
5
  SHA512:
6
- metadata.gz: 36cc14d59e7df9f050844e9406596d69bbf97411ec192d1081b630277dc1de5f18706006f5c41072ccc1983aa23d2638d4a96fb7ed10ec7955e5ed0acee28bdc
7
- data.tar.gz: 9136375cc875cd7db7d29fd7aac2507cca4364f1504432d7328d629b86e795422a2a48239ea1d98915d3217c7f355c74aa598d9133dc49277dda2cb78fdeb3dc
6
+ metadata.gz: e9df5b2875fc19b6a61259938ea99397edb51282c964f7bd511b1709c6625352e7c3d22428eac5ade6617b4a54244fb4b4ffa1574951b8368079fd7428cc5d68
7
+ data.tar.gz: bb8c01ac692e2137f9f0d3ab39a1b7a562ba337145ea0f90a0dd3325a5a67caf523d9f97c0536008adce4815ad15adda1ae036d8ded6f970c16bd761bc7c9a19
@@ -12,6 +12,9 @@ Metrics/LineLength:
12
12
  Metrics/BlockLength:
13
13
  Exclude:
14
14
  - spec/**/*.rb
15
+ Metrics/ModuleLength:
16
+ Exclude:
17
+ - spec/**/*_spec.rb
15
18
 
16
19
  Lint/AmbiguousBlockAssociation:
17
20
  Exclude:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphql_rails (0.3.2)
4
+ graphql_rails (0.3.3)
5
5
  activesupport (>= 4)
6
6
  graphql (~> 1)
7
7
 
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # GraphqlRails
2
2
 
3
- [![Build Status](https://travis-ci.org/povilasjurcys/graphql_rails.svg?branch=master)](https://travis-ci.org/povilasjurcys/graphql_rails)
4
- [![codecov](https://codecov.io/gh/povilasjurcys/graphql_rails/branch/master/graph/badge.svg)](https://codecov.io/gh/povilasjurcys/graphql_rails)
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
5
 
6
6
  Rails style structure for GrapQL API.
7
7
 
File without changes
@@ -0,0 +1,188 @@
1
+ # GraphqlRails
2
+
3
+
4
+ Rails style structure for GrapQL API.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'graphql_rails'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install graphql_rails
21
+
22
+ ## Usage
23
+
24
+ ### Define GraphQL schema as RoR routes
25
+
26
+ ```ruby
27
+ MyGraphqlSchema = GraphqlRails::Router.draw do
28
+ # will create createUser, updateUser, deleteUser mutations and user, users queries.
29
+ # expects that UsersController class exist
30
+ resources :users
31
+
32
+ # if you want custom queries or mutation
33
+ query 'searchLogs', to: 'logs#search' # redirects request to LogsController
34
+ mutation 'changeUserPassword', to: 'users#change_password'
35
+ end
36
+ ```
37
+
38
+ ### Define your Graphql model
39
+
40
+ ```ruby
41
+ class User # works with any class including ActiveRecord
42
+ include GraphqlRails::Model
43
+
44
+ graphql do |c|
45
+ # most common attributes, like :id, :name, :title has default type, so you don't have to specify it (but you can!)
46
+ c.attribute :id
47
+
48
+ c.attribute :email, type: :string
49
+ c.attribute :surname, type: :string
50
+ end
51
+ end
52
+ ```
53
+
54
+ ### Define controller
55
+
56
+ ```ruby
57
+ class UsersController < GraphqlRails::Controller
58
+ # graphql requires to describe which attributes controller action accepts and which returns
59
+ action(:change_user_password)
60
+ .permit(:password!, :id!) # Bang (!) indicates that attribute is required
61
+
62
+ def change_user_password
63
+ user = User.find(params[:id])
64
+ user.update!(password: params[:password])
65
+
66
+ # returned value needs to have all methods defined in model `graphql do` part
67
+ user # or SomeDecorator.new(user)
68
+ end
69
+
70
+ action(:search).permit(search_fields!: SearchFieldsInput) # you can specify your own input fields
71
+ def search
72
+ end
73
+ end
74
+ ```
75
+
76
+ ## Routes
77
+
78
+ ```ruby
79
+ MyGraphqlSchema = GraphqlRails::Router.draw do
80
+ # generates `friend`, `createFriend`, `updateFriend`, `destroyFriend`, `friends` routes
81
+ resources :friends
82
+ resources :shops, only: [:show, :index] # generates `shop` and `shops` routes only
83
+ resources :orders, except: :update # generates all routes except `updateOrder`
84
+
85
+ resources :users do
86
+ # generates `findUser` query
87
+ query :find, on: :member
88
+
89
+ # generates `searchUsers` query
90
+ query :search, on: :collection
91
+ end
92
+
93
+ # you can use namespaced controllers too:
94
+ scope module: 'admin' do
95
+ # `updateTranslations` route will be handeled by `Admin::TranslationsController`
96
+ mutation :updateTranslations, to: 'translations#update'
97
+
98
+ # all :groups routes will be handeled by `Admin::GroupsController`
99
+ resources :groups
100
+ end
101
+ end
102
+ ```
103
+
104
+ ## Testing your GrapqhlRails::Controller in RSpec
105
+
106
+ ### Setup
107
+
108
+ Add those lines in your `spec/spec_helper.rb` file
109
+
110
+ ```ruby
111
+ # spec/spec_helper.rb
112
+ require 'graphql_rails/rspec_controller_helpers'
113
+
114
+ RSpec.configure do |config|
115
+ config.include(GraphqlRails::RSpecControllerHelpers, type: :graphql_controller)
116
+ # ... your other configuration ...
117
+ end
118
+ ```
119
+
120
+ ### Helper methods
121
+
122
+ There are 3 helper methods:
123
+
124
+ * `mutation(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
125
+ * `query(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
126
+ * `response`. Response is set only after you call `mutation` or `query`
127
+
128
+ ### Test examples
129
+
130
+ ```ruby
131
+ class MyGraphqlController
132
+ def index
133
+ "Called from index: #{params[:message]}"
134
+ end
135
+
136
+ action(:create_user).permit(:full_name, :email)
137
+ def create_user
138
+ User.create!(params)
139
+ end
140
+ end
141
+
142
+ RSpec.describe MyGraphqlController, type: :graphql_controller do
143
+ describe '#index' do
144
+ it 'is successful' do
145
+ query(:index)
146
+ expect(response).to be_successful
147
+ end
148
+
149
+ it 'returns correct message' do
150
+ query(:index, params: { message: 'Hello world!' })
151
+ expect(response.result).to eq "Called from index: Hello world!"
152
+ end
153
+ end
154
+
155
+ describe '#create_user' do
156
+ context 'when bad email is given' do
157
+ it 'fails' do
158
+ mutation(:create_user, params { email: 'bad' })
159
+ expect(response).to be_failure
160
+ end
161
+
162
+ it 'contains errors' do
163
+ mutation(:create_user, params { email: 'bad' })
164
+ expect(response.errors).not_to be_empty
165
+ end
166
+ end
167
+ end
168
+ end
169
+ ```
170
+
171
+
172
+ ## Development
173
+
174
+ 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.
175
+
176
+ 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).
177
+
178
+ ## Contributing
179
+
180
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/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.
181
+
182
+ ## License
183
+
184
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
185
+
186
+ ## Code of Conduct
187
+
188
+ 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/[USERNAME]/graphql_rails/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,9 @@
1
+ * [Home](README)
2
+ * Getting started
3
+ * [Setup](getting_started/setup)
4
+ * [Quick start](getting_started/quick_start)
5
+ * Components
6
+ * [Routes](components/routes)
7
+ * [Model](components/model)
8
+ * [Controller](components/controller)
9
+ * [Testing](testing/testing)
@@ -0,0 +1,152 @@
1
+ # Controller
2
+
3
+ Each controller should inherit from `GraphqlRails::Controller`. It is handy to have `ApplicationGraphqlController`:
4
+
5
+ ```ruby
6
+ class ApplicationGraphqlController < GraphqlRails::Controller
7
+ # write your shared code here
8
+ end
9
+ ```
10
+
11
+ ## *action*
12
+
13
+ to specify details about each controller action, you need to call method `action` inside controller. For example:
14
+
15
+ ```ruby
16
+ class ApplicationGraphqlController < GraphqlRails::Controller
17
+ # write your shared code here
18
+ end
19
+ ```
20
+
21
+ ### *permit*
22
+
23
+ ```ruby
24
+ class UsersController < GraphqlRails::Controller
25
+ action(:create).describe('Creates user')
26
+
27
+ def create
28
+ User.create(params)
29
+ end
30
+ end
31
+ ```
32
+
33
+ ### *can_return_nil*
34
+
35
+ By default it is expected that each controller action returns model or array of models. `nil` is not allowed. You can change that by adding `can_return_nil` like this:
36
+
37
+ ```ruby
38
+ class UsersController < GraphqlRails::Controller
39
+ action(:show).permit(:email).can_return_nil
40
+
41
+ def show
42
+ user = User.find_by(email: params[:email])
43
+ return nil if user.blank?
44
+ user
45
+ end
46
+ end
47
+ ```
48
+
49
+ ### *paginated*
50
+
51
+ You can mark collection action as `paginated`. In this case controller will return relay connection type and it will be possible to return only partial results. No need to do anything on controller side (you should always return full list of items)
52
+
53
+ ```ruby
54
+ class UsersController < GraphqlRails::Controller
55
+ action(:index).paginated
56
+
57
+ def index
58
+ User.all
59
+ end
60
+ end
61
+ ```
62
+
63
+ #### *max_page_size*
64
+
65
+ Allows to specify max items count per request
66
+
67
+ ```ruby
68
+ class UsersController < GraphqlRails::Controller
69
+ action(:index).paginated(max_page_size: 10) # add max items limit
70
+
71
+ def index
72
+ User.all # it will render 10 users even you have more
73
+ end
74
+ end
75
+ ```
76
+
77
+ ### *returns*
78
+
79
+ By default return type is determined by controller name. When you want to return some custom object, you can specify that with `returns` method:
80
+
81
+ ```ruby
82
+ class UsersController < GraphqlRails::Controller
83
+ action(:last_order).permit(:id).returns(Order)
84
+
85
+ def last_order
86
+ user = User.find(params[:id]).orders.last
87
+ end
88
+ end
89
+ ```
90
+
91
+ ### *describe*
92
+
93
+ If you want to improve graphql documentation, you can add description for each action. To do so, use `describe` method:
94
+
95
+ ```ruby
96
+ class UsersController < GraphqlRails::Controller
97
+ action(:create).describe('Creates user')
98
+
99
+ def create
100
+ User.create(params)
101
+ end
102
+ end
103
+ ```
104
+
105
+ ## *before_action*
106
+
107
+ You can add `before_action` to run some filters before calling your controller action. Here is an example:
108
+
109
+ ```ruby
110
+ class UsersController < GraphqlRails::Controller
111
+ before_action :require_auth_token
112
+
113
+ def create
114
+ User.create(params)
115
+ end
116
+
117
+ private
118
+
119
+ def require_auth_token # will run before `UsersController#create` action
120
+ raise 'Not authenticated' unless User.where(token: params[:token]).exist?
121
+ end
122
+ end
123
+ ```
124
+
125
+ ### *only* and *except* option
126
+
127
+ `UsersController.before_action` accepts `only` or `except` options which allows to skip filters for some actions.
128
+
129
+ ```ruby
130
+ class UsersController < GraphqlRails::Controller
131
+ before_action :require_auth_token, except: :show
132
+ before_action :require_admin_token, only: %i[update destroy]
133
+
134
+ def create
135
+ User.create(params)
136
+ end
137
+
138
+ def destroy
139
+ User.create(params)
140
+ end
141
+
142
+ private
143
+
144
+ def require_auth_token
145
+ raise 'Not authenticated' unless User.where(token: params[:token]).exist?
146
+ end
147
+
148
+ def require_auth_token
149
+ raise 'Admin not authenticated' unless Admin.where(token: params[:admin_token]).exist?
150
+ end
151
+ end
152
+ ```
@@ -0,0 +1,123 @@
1
+ # Model
2
+
3
+ To make your model graphql-firendly, you need to inlcude `GraphqlRails::Model`. Your model can be any ruby class (PORO, ActiveRecord::Base or anything else)
4
+
5
+ Also you need to define which attributes can be exposed via graphql. To do so, use `graphql` method inside your model body. Example:
6
+
7
+ ```ruby
8
+ class User # works with any class including ActiveRecord
9
+ include GraphqlRails::Model
10
+
11
+ graphql do |c|
12
+ c.attribute :id
13
+ c.full_name, type: :string
14
+ end
15
+ end
16
+ ```
17
+
18
+ ## _graphql_
19
+
20
+ This method must be called inside your model body. `grapqhl` is used for making your model convertible to graphql type.
21
+
22
+ ### _attribute_
23
+
24
+ Most commonly you will use `attribute` to make your model methods and attributes visible via graphql endpoint.
25
+
26
+ #### _type_
27
+
28
+ Some types can be determined by attribute name, so you can skip this attribute:
29
+
30
+ * attributes which ends with name `*_id` has `ID` type
31
+ * attributes which ends with `?` has `Boolean` type
32
+ * all other attributes without type are considered to be `String`
33
+
34
+ available types are:
35
+
36
+ * ID: `'id'`
37
+ * String: `'string'`, `'str'`, `'text'`
38
+ * Boolean: `'bool'`, `'boolean'`
39
+ * Float: `'float'`, `'double'`, `'decimal'`
40
+
41
+ usage example:
42
+
43
+ ```ruby
44
+ class User
45
+ include GraphqlRails::Model
46
+
47
+ graphql do |c|
48
+ c.attribute :shop_id # ID type
49
+ c.attribute :full_name # String type
50
+ c.attribute :admin? # Boolean type
51
+ c.attribute :level, type: 'integer'
52
+ c.attribute :money, type: 'float'
53
+ end
54
+ end
55
+ ```
56
+
57
+ #### _property_
58
+
59
+ By default graphql attribute names are expected to be same as model methods/attributes, but if you want to use different name on grapqhl side, you can use `propery` option:
60
+
61
+ ```
62
+ class User
63
+ include GraphqlRails::Model
64
+
65
+ graphql do |c|
66
+ c.attribute :shop_id, property: :department_id
67
+ end
68
+
69
+ def department_id
70
+ 456
71
+ end
72
+ end
73
+ ```
74
+
75
+ #### _description_
76
+
77
+ You can also describe each attribute and make graphql documentation even more readable. To do so, add `description` option:
78
+
79
+ ```
80
+ class User
81
+ include GraphqlRails::Model
82
+
83
+ graphql do |c|
84
+ c.attribute :shop_id, description: 'references to shop'
85
+ end
86
+ end
87
+ ```
88
+
89
+ ### _name_
90
+
91
+ By default grapqhl type name will be same as model name, but you can change it via `name` method
92
+
93
+ ```ruby
94
+ class User
95
+ include GraphqlRails::Model
96
+
97
+ graphql do |c|
98
+ c.name 'Employee'
99
+ end
100
+ end
101
+ ```
102
+
103
+ ### _description_
104
+
105
+ To improve grapqhl documentation, you can description for your graphql type:
106
+
107
+ ```ruby
108
+ class User
109
+ include GraphqlRails::Model
110
+
111
+ graphql do |c|
112
+ c.description 'Users are awesome!'
113
+ end
114
+ end
115
+ ```
116
+
117
+ ### *graphql_type*
118
+
119
+ Sometimes it's handy to get raw graphql type. To do so you can call:
120
+
121
+ ```ruby
122
+ YourModel.graphql.grapqhl_type
123
+ ```
@@ -0,0 +1,87 @@
1
+ # Routes
2
+
3
+ Routes are generated via `GraphqlRails::Router.draw` method. It is very similar to rails router, except that instead of `match`, `get`, `post` actions you have `query` and `mutation` actions. In most cases you will use `resources` action. It works same as in rails router.
4
+
5
+ Here is simple router example:
6
+
7
+ ```ruby
8
+ MyGraphqlSchema = GraphqlRails::Router.draw do
9
+ # generates `friend`, `createFriend`, `updateFriend`, `destroyFriend`, `friends` routes
10
+ resources :friends
11
+ resources :shops, only: [:show, :index] # generates `shop` and `shops` routes only
12
+ resources :orders, except: :update # generates all routes except `updateOrder`
13
+
14
+ resources :users do
15
+ # generates `findUser` query
16
+ query :find, on: :member
17
+
18
+ # generates `searchUsers` query
19
+ query :search, on: :collection
20
+ end
21
+
22
+ # you can use namespaced controllers too:
23
+ scope module: 'admin' do
24
+ # `updateTranslations` route will be handeled by `Admin::TranslationsController`
25
+ mutation :updateTranslations, to: 'translations#update'
26
+
27
+ # all :groups routes will be handeled by `Admin::GroupsController`
28
+ resources :groups
29
+ end
30
+ end
31
+ ```
32
+
33
+ ## _resources_
34
+
35
+ `resources` method generates routes to `index`, `show`, `create`, `update` and `destroy` controller actions.
36
+
37
+ ### _only_ and _except_ option
38
+
39
+ If you want to exclude some actions you can use `only` or `except` options.
40
+
41
+ ```ruby
42
+ MyGraphqlSchema = GraphqlRails::Router.draw do
43
+ resouces :users
44
+ resouces :friends, only: :index
45
+ resouces :posts, except: [:destroy, :index]
46
+ end
47
+ ```
48
+
49
+ ### custom actions
50
+
51
+ Sometimes it's handy so have non-CRUD actions in your controller. To define such route you can call `resources` with a block:
52
+
53
+ ```ruby
54
+ MyGraphqlSchema = GraphqlRails::Router.draw do
55
+ resouces :users do
56
+ mutation :changePassword, on: :member
57
+ query :active, on: :collection
58
+ end
59
+ end
60
+ ```
61
+
62
+ ## _query_ and _mutation_
63
+
64
+ in case you want to have non-CRUD controller with custom actions you can define your own `query`/`mutation` actions like this:
65
+
66
+ ```ruby
67
+ MyGraphqlSchema = GraphqlRails::Router.draw do
68
+ mutation :logIn, to: 'sessions#login'
69
+ query :me, to 'users#current_user'
70
+ end
71
+ ```
72
+
73
+ ## _scope_
74
+
75
+ ### _module_ options
76
+
77
+ currently `scope` method accepts single option: `module`. `module` allows to specify controller namespace. So you can use scoped controllers, like so:
78
+
79
+ ```ruby
80
+ MyGraphqlSchema = GraphqlRails::Router.draw do
81
+ scope module: 'admin/top_secret' do
82
+ mutation :logIn, to: 'sessions#login' # this will trigger Admin::TopSecret::SessionsController
83
+ end
84
+
85
+ mutation :logIn, to: 'sessions#login' # this will trigger ::SessionsController
86
+ end
87
+ ```
@@ -0,0 +1,55 @@
1
+ # Quick Start
2
+
3
+ ## Define GraphQL schema as RoR routes
4
+
5
+ ```ruby
6
+ MyGraphqlSchema = GraphqlRails::Router.draw do
7
+ # will create createUser, updateUser, deleteUser mutations and user, users queries.
8
+ # expects that UsersController class exist
9
+ resources :users
10
+
11
+ # if you want custom queries or mutation
12
+ query 'searchLogs', to: 'logs#search' # redirects request to LogsController
13
+ mutation 'changeUserPassword', to: 'users#change_password'
14
+ end
15
+ ```
16
+
17
+ ## Define your Graphql model
18
+
19
+ ```ruby
20
+ class User # works with any class including ActiveRecord
21
+ include GraphqlRails::Model
22
+
23
+ graphql do |c|
24
+ # most common attributes, like :id, :name, :title has default type, so you don't have to specify it (but you can!)
25
+ c.attribute :id
26
+
27
+ c.attribute :email, :string
28
+ c.attribute :surname, :string
29
+ end
30
+ end
31
+ ```
32
+
33
+ ## Define controller
34
+
35
+ ```ruby
36
+ class UsersController < GraphqlRails::Controller
37
+ # graphql requires to describe which attributes controller action accepts and which returns
38
+ action(:change_user_password)
39
+ .permit(:password!, :id!) # Bang (!) indicates that attribute is required
40
+
41
+ def change_user_password
42
+ user = User.find(params[:id])
43
+ user.update!(password: params[:password])
44
+
45
+ # returned value needs to have all methods defined in model `graphql do` part
46
+ user # or SomeDecorator.new(user)
47
+ end
48
+
49
+ action(:search).permit(search_fields!: SearchFieldsInput) # you can specify your own input fields
50
+ def search
51
+ end
52
+ end
53
+ ```
54
+
55
+ Congrats, you are done!
@@ -0,0 +1,16 @@
1
+ ## Setup
2
+
3
+ Add this line to your application's Gemfile:
4
+
5
+ ```ruby
6
+ gem 'graphql_rails'
7
+ ```
8
+
9
+ And then execute:
10
+
11
+ $ bundle
12
+
13
+ Or install it yourself as:
14
+
15
+ $ gem install graphql_rails
16
+
@@ -0,0 +1,70 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Document</title>
6
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
7
+ <meta name="description" content="Description">
8
+ <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
9
+ <link rel="stylesheet" href="https://unpkg.com/docsify/lib/themes/vue.css">
10
+ </head>
11
+ <body>
12
+ <div id="app"></div>
13
+ <script>
14
+ function parseQueryString (queryString) {
15
+ var params = {};
16
+ var temp;
17
+ // Split into key/value pairs
18
+ queries = queryString.split("&");
19
+ // Convert the array of strings into an object
20
+ for (var i = 0, l = queries.length; i < l; i++ ) {
21
+ temp = queries[i].split('=');
22
+ params[temp[0]] = temp[1];
23
+ }
24
+ return params;
25
+ };
26
+
27
+ function getJsonFromUrl() {
28
+ return parseQueryString(location.search.substr(1));
29
+ }
30
+
31
+ window.$docsify = {
32
+ auto2top: true,
33
+ name: 'GraphqlRails',
34
+ repo: 'https://github.com/samesystem/graphql_rails',
35
+ subMaxLevel: 3,
36
+ loadSidebar: true,
37
+ formatUpdated: '{MM}/{DD} {HH}:{mm}',
38
+ branchBasePath: 'https://raw.githubusercontent.com/samesystem/graphql_rails/',
39
+ plugins: [
40
+ function (hook, vm) { // reasign any config value by param attribute
41
+ Object.assign(window.$docsify, getJsonFromUrl());
42
+ },
43
+
44
+ function (hook, vm) { // allow to change branch
45
+ if (!window.$docsify.branchBasePath || !window.$docsify.branch) {
46
+ return;
47
+ }
48
+
49
+ var branch = window.$docsify.branch;
50
+ var basePath = window.$docsify.branchBasePath + branch;
51
+ window.$docsify.basePath = basePath;
52
+ },
53
+
54
+ function (hook, vm) { // add edit page link
55
+ hook.beforeEach(function (html) {
56
+ var branch = window.$docsify.branch || 'master'
57
+ var url = 'https://github.com/samesystem/graphql_rails/edit/' + branch + '/docs/' + vm.route.file
58
+ var editHtml = '[:memo: Edit Document](' + url + ')\n'
59
+ return html
60
+ + '\n\n----\n\n'
61
+ + editHtml
62
+ })
63
+ }
64
+ ]
65
+ }
66
+ </script>
67
+ <script src="https://unpkg.com/docsify/lib/docsify.js"></script>
68
+ <script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
69
+ </body>
70
+ </html>
@@ -0,0 +1,68 @@
1
+ # Testing
2
+
3
+ ## Testing graphql controllers in RSpec
4
+
5
+ ### Setup
6
+
7
+ Add those lines in your `spec/spec_helper.rb` file
8
+
9
+ ```ruby
10
+ # spec/spec_helper.rb
11
+ require 'graphql_rails/rspec_controller_helpers'
12
+
13
+ RSpec.configure do |config|
14
+ config.include(GraphqlRails::RSpecControllerHelpers, type: :graphql_controller)
15
+ # ... your other configuration ...
16
+ end
17
+ ```
18
+
19
+ ### Helper methods
20
+
21
+ There are 3 helper methods:
22
+
23
+ * `mutation(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
24
+ * `query(:your_controller_action_name, params: {}, context: {})`. `params` and `context` are optional
25
+ * `response`. Response is set only after you call `mutation` or `query`
26
+
27
+ ### Test examples
28
+
29
+ ```ruby
30
+ class MyGraphqlController
31
+ def index
32
+ "Called from index: #{params[:message]}"
33
+ end
34
+
35
+ action(:create_user).permit(:full_name, :email)
36
+ def create_user
37
+ User.create!(params)
38
+ end
39
+ end
40
+
41
+ RSpec.describe MyGraphqlController, type: :graphql_controller do
42
+ describe '#index' do
43
+ it 'is successful' do
44
+ query(:index)
45
+ expect(response).to be_successful
46
+ end
47
+
48
+ it 'returns correct message' do
49
+ query(:index, params: { message: 'Hello world!' })
50
+ expect(response.result).to eq "Called from index: Hello world!"
51
+ end
52
+ end
53
+
54
+ describe '#create_user' do
55
+ context 'when bad email is given' do
56
+ it 'fails' do
57
+ mutation(:create_user, params { email: 'bad' })
58
+ expect(response).to be_failure
59
+ end
60
+
61
+ it 'contains errors' do
62
+ mutation(:create_user, params { email: 'bad' })
63
+ expect(response.errors).not_to be_empty
64
+ end
65
+ end
66
+ end
67
+ end
68
+ ```
@@ -9,12 +9,12 @@ module GraphqlRails
9
9
  # base class for all graphql_rails controllers
10
10
  class Controller
11
11
  class << self
12
- def before_action(action_name)
13
- controller_configuration.add_before_action(action_name)
12
+ def before_action(*args)
13
+ controller_configuration.add_before_action(*args)
14
14
  end
15
15
 
16
- def action(method_name)
17
- controller_configuration.action(method_name)
16
+ def action(action_name)
17
+ controller_configuration.action(action_name)
18
18
  end
19
19
 
20
20
  def controller_configuration
@@ -55,9 +55,11 @@ module GraphqlRails
55
55
 
56
56
  private
57
57
 
58
- def call_with_rendering(method_name)
59
- self.class.controller_configuration.before_actions.each { |action_name| send(action_name) }
60
- response = public_send(method_name)
58
+ def call_with_rendering(action_name)
59
+ before_actions = self.class.controller_configuration.before_actions_for(action_name)
60
+ before_actions.each { |before_action| send(before_action.name) }
61
+ response = public_send(action_name)
62
+
61
63
  render response if graphql_request.no_object_to_return?
62
64
  rescue StandardError => error
63
65
  render error: error
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphqlRails
4
+ class Controller
5
+ # stores information about controller filter
6
+ class BeforeActionFilter
7
+ attr_reader :name
8
+
9
+ def initialize(name, only: [], except: [])
10
+ @name = name
11
+ @only_actions = Array(only).map(&:to_sym)
12
+ @except_actions = Array(except).map(&:to_sym)
13
+ end
14
+
15
+ def applicable_for?(action_name)
16
+ if only_actions.any?
17
+ only_actions.include?(action_name.to_sym)
18
+ elsif except_actions.any?
19
+ !except_actions.include?(action_name.to_sym)
20
+ else
21
+ true
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :only_actions, :except_actions
28
+ end
29
+ end
30
+ end
@@ -3,21 +3,25 @@
3
3
  require 'active_support/core_ext/string/inflections'
4
4
  require 'graphql_rails/attribute'
5
5
  require 'graphql_rails/controller/action_configuration'
6
+ require 'graphql_rails/controller/before_action_filter'
6
7
 
7
8
  module GraphqlRails
8
9
  class Controller
9
10
  # stores all graphql_rails contoller specific config
10
11
  class Configuration
11
- attr_reader :before_actions
12
-
13
12
  def initialize(controller)
14
13
  @controller = controller
15
- @before_actions = Set.new
14
+ @before_actions = {}
16
15
  @action_by_name = {}
17
16
  end
18
17
 
19
- def add_before_action(name)
20
- before_actions << name
18
+ def before_actions_for(action_name)
19
+ before_actions.values.select { |action| action.applicable_for?(action_name) }
20
+ end
21
+
22
+ def add_before_action(name, **options)
23
+ symbolized_name = name.to_sym
24
+ before_actions[symbolized_name] = BeforeActionFilter.new(symbolized_name, **options)
21
25
  end
22
26
 
23
27
  def action(method_name)
@@ -26,7 +30,7 @@ module GraphqlRails
26
30
 
27
31
  private
28
32
 
29
- attr_reader :controller
33
+ attr_reader :controller, :before_actions
30
34
  end
31
35
  end
32
36
  end
@@ -9,6 +9,12 @@ module GraphqlRails
9
9
  class Configuration
10
10
  attr_reader :attributes
11
11
 
12
+ COUNT_TOTAL_ITEMS = lambda do |obj, _args, _ctx|
13
+ obj_nodes = obj.nodes
14
+ obj_nodes = obj_nodes.except(:offset) if obj_nodes.is_a?(ActiveRecord::Relation)
15
+ obj_nodes.size
16
+ end
17
+
12
18
  def initialize(model_class)
13
19
  @model_class = model_class
14
20
  @attributes = {}
@@ -42,7 +48,7 @@ module GraphqlRails
42
48
  def connection_type
43
49
  @connection_type ||= begin
44
50
  graphql_type.define_connection do
45
- field :total, types.Int, resolve: ->(obj, _args, _ctx) { obj.nodes.size }
51
+ field :total, types.Int, resolve: COUNT_TOTAL_ITEMS
46
52
  end
47
53
  end
48
54
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GraphqlRails
4
- VERSION = '0.3.2'
4
+ VERSION = '0.3.3'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Povilas Jurčys
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-07-20 00:00:00.000000000 Z
11
+ date: 2018-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -101,6 +101,16 @@ files:
101
101
  - Rakefile
102
102
  - bin/console
103
103
  - bin/setup
104
+ - docs/.nojekyll
105
+ - docs/README.md
106
+ - docs/_sidebar.md
107
+ - docs/components/controller.md
108
+ - docs/components/model.md
109
+ - docs/components/routes.md
110
+ - docs/getting_started/quick_start.md
111
+ - docs/getting_started/setup.md
112
+ - docs/index.html
113
+ - docs/testing/testing.md
104
114
  - graphql_rails.gemspec
105
115
  - lib/graphql_rails.rb
106
116
  - lib/graphql_rails/attribute.rb
@@ -108,6 +118,7 @@ files:
108
118
  - lib/graphql_rails/controller.rb
109
119
  - lib/graphql_rails/controller/action.rb
110
120
  - lib/graphql_rails/controller/action_configuration.rb
121
+ - lib/graphql_rails/controller/before_action_filter.rb
111
122
  - lib/graphql_rails/controller/configuration.rb
112
123
  - lib/graphql_rails/controller/controller_function.rb
113
124
  - lib/graphql_rails/controller/format_results.rb