apiql 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +31 -18
- data/apiql.gemspec +1 -1
- data/assets/javascripts/apiql.js +5 -5
- data/lib/apiql.rb +82 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0df2f76cbbbf87e6a3b506c598a7e41ef620dc283ddc345cd157d2fc80661848
|
4
|
+
data.tar.gz: c6a9b1b1af21e094684ce86ea61f2a26f1f8432ed00f4657f8272429bea3df22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b41c1af521d8feb114c107af996868d5d4a7ceaade3d20a4251c5881f8e54aeab5dbaf071c6a943650edaa00a21b066e9fea87b827bdbb9103d4a5fb128bab3c
|
7
|
+
data.tar.gz: 38d9b8b00bbf2cf92f940629b9fe76192aa1b702b5cf10364ba03d757c81eca0e5fbc21f3987391d08ea6ddb6ed4b2d5fe103e26a4bc59e9bbc216da8f834be8
|
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Implementation of the API language similar to GraphQL for Ruby on Rails.
|
|
4
4
|
|
5
5
|
It compiles requests into Hashes for faster rendering.
|
6
6
|
|
7
|
-
|
7
|
+
It automatically detects nested entities and eager-loads them for faster DB access!
|
8
8
|
|
9
9
|
Define your responder (requested methods):
|
10
10
|
|
@@ -31,16 +31,16 @@ class UserAPIQL < ::APIQL
|
|
31
31
|
end
|
32
32
|
|
33
33
|
```
|
34
|
-
In controller or Grape API endpoint, handler of POST /
|
34
|
+
In controller or Grape API endpoint, handler of POST /apiql method (or any other, see below APIQL.endpoint):
|
35
35
|
|
36
36
|
```ruby
|
37
|
-
def
|
37
|
+
def apiql
|
38
38
|
schema = APIQL.cache(params)
|
39
39
|
UserAPIQL.new(self, :session, :current_user, :params).render(schema)
|
40
40
|
end
|
41
41
|
|
42
42
|
```
|
43
|
-
variables `session`, `current_user` and `params` (you can list any you need) will be stored into context you can use in presenters and handlers
|
43
|
+
variables `session`, `current_user` and `params` (you can list any you need in your presenters/responders) will be stored into context you can use in presenters and handlers
|
44
44
|
|
45
45
|
Define presenters for your models:
|
46
46
|
|
@@ -66,14 +66,14 @@ assets/javascripts/application.js:
|
|
66
66
|
|
67
67
|
```javascript
|
68
68
|
//= require apiql
|
69
|
-
APIQL.endpoint = "/"
|
69
|
+
APIQL.endpoint = "/apiql"
|
70
70
|
```
|
71
71
|
|
72
72
|
```javascript
|
73
|
-
// function apiql(
|
73
|
+
// function apiql(schema, params = {}, form = null) -- schema is cached, so entire request is passed only for first time, later - short hashes only
|
74
74
|
|
75
75
|
authenticate(email, password) {
|
76
|
-
apiql(
|
76
|
+
apiql(`
|
77
77
|
logout()
|
78
78
|
|
79
79
|
authenticate(email, password) {
|
@@ -88,7 +88,7 @@ authenticate(email, password) {
|
|
88
88
|
}
|
89
89
|
}
|
90
90
|
`, {
|
91
|
-
email: email, // these
|
91
|
+
email: email, // these vars will be passed into methods on the server side
|
92
92
|
password: password
|
93
93
|
})
|
94
94
|
.then(response => { // response contains results of called methods
|
@@ -97,7 +97,7 @@ authenticate(email, password) {
|
|
97
97
|
}
|
98
98
|
|
99
99
|
logout() {
|
100
|
-
apiql(
|
100
|
+
apiql(`
|
101
101
|
logout
|
102
102
|
`)
|
103
103
|
.then(response => {
|
@@ -109,12 +109,12 @@ logout() {
|
|
109
109
|
you can call methods on entities:
|
110
110
|
|
111
111
|
```javascript
|
112
|
-
apiql(
|
112
|
+
apiql(`
|
113
113
|
authenticate(email, password) {
|
114
114
|
token
|
115
115
|
}
|
116
116
|
|
117
|
-
me.reload {
|
117
|
+
user: me.reload {
|
118
118
|
email full_name role token
|
119
119
|
|
120
120
|
roles(filter) {
|
@@ -132,7 +132,7 @@ you can call methods on entities:
|
|
132
132
|
password: password
|
133
133
|
})
|
134
134
|
.then(response => {
|
135
|
-
let user = response
|
135
|
+
let user = response.user
|
136
136
|
})
|
137
137
|
}
|
138
138
|
```
|
@@ -143,12 +143,6 @@ config/initializers/apiql.rb:
|
|
143
143
|
|
144
144
|
```ruby
|
145
145
|
class APIQL
|
146
|
-
delegate :authorize!, to: :@context
|
147
|
-
|
148
|
-
class Entity
|
149
|
-
delegate :authorize!, to: :@context
|
150
|
-
end
|
151
|
-
|
152
146
|
class Context
|
153
147
|
def authorize!(*args)
|
154
148
|
ability.authorize!(*args)
|
@@ -182,3 +176,22 @@ class User < ApplicationRecord
|
|
182
176
|
end
|
183
177
|
|
184
178
|
```
|
179
|
+
|
180
|
+
you can add CRUD methods for your models:
|
181
|
+
|
182
|
+
```ruby
|
183
|
+
class UserAPIQL < ::APIQL
|
184
|
+
model ::User
|
185
|
+
model ::Role
|
186
|
+
end
|
187
|
+
```
|
188
|
+
|
189
|
+
or mount methods from external modules:
|
190
|
+
|
191
|
+
```ruby
|
192
|
+
class UserAPIQL < ::APIQL
|
193
|
+
mount ::Services::User # all methouds could be called with "user" prefix like "user.logout()"
|
194
|
+
mount ::Services::Common, as: '' # all methods could be called without prefixes
|
195
|
+
mount ::Services::Employer, as: 'dashboard" # all methods could be called with specified prefix
|
196
|
+
end
|
197
|
+
```
|
data/apiql.gemspec
CHANGED
data/assets/javascripts/apiql.js
CHANGED
@@ -13,7 +13,7 @@ const APIQL = {
|
|
13
13
|
return hash
|
14
14
|
},
|
15
15
|
|
16
|
-
call(
|
16
|
+
call(schema, params = {}, form = null) {
|
17
17
|
return new Promise((resolve, reject) => {
|
18
18
|
if(params instanceof FormData) {
|
19
19
|
form = params
|
@@ -32,7 +32,7 @@ const APIQL = {
|
|
32
32
|
params.apiql = this.hash(schema)
|
33
33
|
}
|
34
34
|
|
35
|
-
Vue.http.post(
|
35
|
+
Vue.http.post(APIQL.endpoint, form || params)
|
36
36
|
.then(response => {
|
37
37
|
resolve(response.body)
|
38
38
|
})
|
@@ -50,7 +50,7 @@ const APIQL = {
|
|
50
50
|
params.apiql_request = schema
|
51
51
|
}
|
52
52
|
|
53
|
-
Vue.http.post(
|
53
|
+
Vue.http.post(APIQL.endpoint, form || params)
|
54
54
|
.then(response => {
|
55
55
|
resolve(response.body)
|
56
56
|
})
|
@@ -66,6 +66,6 @@ const APIQL = {
|
|
66
66
|
}
|
67
67
|
}
|
68
68
|
|
69
|
-
function apiql(
|
70
|
-
return APIQL.call(
|
69
|
+
function apiql(schema, params = {}, form = null) {
|
70
|
+
return APIQL.call(schema, params, form)
|
71
71
|
}
|
data/lib/apiql.rb
CHANGED
@@ -7,12 +7,90 @@ class APIQL
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
module CRUD
|
11
|
+
def model(klass)
|
12
|
+
define_method "#{klass.name.pluralize.underscore}" do |page = nil, page_size = 10|
|
13
|
+
authorize! :read, klass
|
14
|
+
|
15
|
+
if page.present?
|
16
|
+
{
|
17
|
+
total: klass.count,
|
18
|
+
items: klass.offset(page * page_size).limit(page_size)
|
19
|
+
}
|
20
|
+
else
|
21
|
+
klass.all
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method "#{klass.name.underscore}" do |id|
|
26
|
+
item = klass.find(id)
|
27
|
+
|
28
|
+
authorize! :read, item
|
29
|
+
|
30
|
+
item
|
31
|
+
end
|
32
|
+
|
33
|
+
define_method "#{klass.name.underscore}.create" do |params|
|
34
|
+
authorize! :create, klass
|
35
|
+
|
36
|
+
klass_entity = "#{klass.name}::Entity".constantize
|
37
|
+
|
38
|
+
if klass_entity.respond_to?(:create_params, params)
|
39
|
+
params = klass_entity.send(:create_params, params)
|
40
|
+
elsif klass_entity.respond_to?(:params, params)
|
41
|
+
params = klass_entity.send(:params, params)
|
42
|
+
end
|
43
|
+
|
44
|
+
klass.create!(params)
|
45
|
+
end
|
46
|
+
|
47
|
+
define_method "#{klass.name.underscore}.update" do |id, params|
|
48
|
+
item = klass.find(id)
|
49
|
+
|
50
|
+
authorize! :update, item
|
51
|
+
|
52
|
+
klass_entity = "#{klass.name}::Entity".constantize
|
53
|
+
|
54
|
+
if klass_entity.respond_to?(:update_params, params)
|
55
|
+
params = klass_entity.send(:update_params, params)
|
56
|
+
elsif klass_entity.respond_to?(:params, params)
|
57
|
+
params = klass_entity.send(:params, params)
|
58
|
+
end
|
59
|
+
|
60
|
+
item.update!(params)
|
61
|
+
end
|
62
|
+
|
63
|
+
define_method "#{klass.name.underscore}.destroy" do |id|
|
64
|
+
item = klass.find(id)
|
65
|
+
|
66
|
+
authorize! :destroy, item
|
67
|
+
|
68
|
+
item.destroy!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
10
73
|
class Error < StandardError; end
|
11
74
|
class CacheMissed < StandardError; end
|
12
75
|
|
13
76
|
attr_reader :context
|
77
|
+
delegate :authorize!, to: :@context
|
14
78
|
|
15
79
|
class << self
|
80
|
+
include ::APIQL::CRUD
|
81
|
+
|
82
|
+
def mount(klass, as: nil)
|
83
|
+
as ||= klass.name.split('::').last.underscore
|
84
|
+
as += '.' if as.present?
|
85
|
+
|
86
|
+
klass.instance_methods(false).each do |method|
|
87
|
+
klass.alias_method("#{as}#{method}", method)
|
88
|
+
klass.remove_method(method) if as.present?
|
89
|
+
end
|
90
|
+
|
91
|
+
include klass
|
92
|
+
end
|
93
|
+
|
16
94
|
@@cache = {}
|
17
95
|
|
18
96
|
def cache(params)
|
@@ -185,6 +263,8 @@ class APIQL
|
|
185
263
|
private
|
186
264
|
|
187
265
|
class Entity
|
266
|
+
delegate :authorize!, to: :@context
|
267
|
+
|
188
268
|
class << self
|
189
269
|
attr_reader :apiql_attributes
|
190
270
|
|
@@ -350,6 +430,8 @@ class APIQL
|
|
350
430
|
end
|
351
431
|
end
|
352
432
|
|
433
|
+
def authorize!(*args); end
|
434
|
+
|
353
435
|
def inject_delegators(target)
|
354
436
|
@fields.each do |field|
|
355
437
|
target.class_eval do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apiql
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dmitry Silchenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|