json_apiable 0.3 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +39 -0
- data/Gemfile.lock +107 -104
- data/README.md +75 -3
- data/json_apiable.gemspec +4 -4
- data/lib/json_apiable.rb +6 -1
- data/lib/json_apiable/base_filter.rb +24 -0
- data/lib/json_apiable/configuration.rb +3 -1
- data/lib/json_apiable/core_extensions.rb +3 -1
- data/lib/json_apiable/errors.rb +3 -1
- data/lib/json_apiable/filter_matchers.rb +67 -0
- data/lib/json_apiable/filter_parser.rb +72 -0
- data/lib/json_apiable/json_apiable.rb +30 -14
- data/lib/json_apiable/pagination_parser.rb +10 -9
- data/lib/json_apiable/params_parser.rb +7 -3
- data/lib/json_apiable/renderers.rb +8 -1
- data/lib/json_apiable/version.rb +3 -1
- metadata +22 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8badac374f5beeb1a450a13c9e15a9b51ecf3f7999a1584037df80234746365e
|
|
4
|
+
data.tar.gz: 9731a6810c7bde962dfd7ff5874f18366b6bb378a7a0e4358200249ef12f569b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e0a1e8c16896ba6bb97165654a6fa31d2565eb2ae03a9a1fb464ee44f62cbf73b9556fc1f68366b2b3a54665bcd2ad66e84c7947200efe345a3de185f3259a60
|
|
7
|
+
data.tar.gz: 31e1bc0ce9505acc7234cc6dc0f1866ee1f7aa99411acedac3bff8db8d74360fa256b6e3fa11c969f2c8b6bb68f352604b5419f6b4c980fbe727975de63d48d4
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 2.4
|
|
3
|
+
Exclude:
|
|
4
|
+
- 'db/**/*'
|
|
5
|
+
- 'bin/**/*'
|
|
6
|
+
- 'config/**/*'
|
|
7
|
+
- 'spec/**/*'
|
|
8
|
+
- 'json_apiable.gemspec'
|
|
9
|
+
- 'Gemfile'
|
|
10
|
+
- 'Rakefile'
|
|
11
|
+
|
|
12
|
+
Metrics:
|
|
13
|
+
Enabled: false
|
|
14
|
+
|
|
15
|
+
Naming/AccessorMethodName:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
Style/PercentLiteralDelimiters:
|
|
19
|
+
Enabled: false
|
|
20
|
+
|
|
21
|
+
Style/HashSyntax:
|
|
22
|
+
Enabled: false
|
|
23
|
+
|
|
24
|
+
Style/Documentation:
|
|
25
|
+
Enabled: false
|
|
26
|
+
|
|
27
|
+
Style/StringLiterals:
|
|
28
|
+
Enabled: false
|
|
29
|
+
|
|
30
|
+
Style/ClassAndModuleChildren:
|
|
31
|
+
Enabled: false
|
|
32
|
+
|
|
33
|
+
Style/SymbolArray:
|
|
34
|
+
Enabled: false
|
|
35
|
+
|
|
36
|
+
Layout/DotPosition:
|
|
37
|
+
EnforcedStyle: trailing
|
|
38
|
+
|
|
39
|
+
|
data/Gemfile.lock
CHANGED
|
@@ -1,127 +1,131 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
json_apiable (0.
|
|
5
|
-
activerecord
|
|
6
|
-
activesupport
|
|
7
|
-
|
|
4
|
+
json_apiable (0.5)
|
|
5
|
+
activerecord
|
|
6
|
+
activesupport
|
|
7
|
+
jsonapi-serializer
|
|
8
8
|
|
|
9
9
|
GEM
|
|
10
10
|
remote: https://rubygems.org/
|
|
11
11
|
specs:
|
|
12
|
-
actioncable (6.
|
|
13
|
-
actionpack (= 6.
|
|
12
|
+
actioncable (6.1.3.1)
|
|
13
|
+
actionpack (= 6.1.3.1)
|
|
14
|
+
activesupport (= 6.1.3.1)
|
|
14
15
|
nio4r (~> 2.0)
|
|
15
16
|
websocket-driver (>= 0.6.1)
|
|
16
|
-
actionmailbox (6.
|
|
17
|
-
actionpack (= 6.
|
|
18
|
-
activejob (= 6.
|
|
19
|
-
activerecord (= 6.
|
|
20
|
-
activestorage (= 6.
|
|
21
|
-
activesupport (= 6.
|
|
17
|
+
actionmailbox (6.1.3.1)
|
|
18
|
+
actionpack (= 6.1.3.1)
|
|
19
|
+
activejob (= 6.1.3.1)
|
|
20
|
+
activerecord (= 6.1.3.1)
|
|
21
|
+
activestorage (= 6.1.3.1)
|
|
22
|
+
activesupport (= 6.1.3.1)
|
|
22
23
|
mail (>= 2.7.1)
|
|
23
|
-
actionmailer (6.
|
|
24
|
-
actionpack (= 6.
|
|
25
|
-
actionview (= 6.
|
|
26
|
-
activejob (= 6.
|
|
24
|
+
actionmailer (6.1.3.1)
|
|
25
|
+
actionpack (= 6.1.3.1)
|
|
26
|
+
actionview (= 6.1.3.1)
|
|
27
|
+
activejob (= 6.1.3.1)
|
|
28
|
+
activesupport (= 6.1.3.1)
|
|
27
29
|
mail (~> 2.5, >= 2.5.4)
|
|
28
30
|
rails-dom-testing (~> 2.0)
|
|
29
|
-
actionpack (6.
|
|
30
|
-
actionview (= 6.
|
|
31
|
-
activesupport (= 6.
|
|
32
|
-
rack (~> 2.0, >= 2.0.
|
|
31
|
+
actionpack (6.1.3.1)
|
|
32
|
+
actionview (= 6.1.3.1)
|
|
33
|
+
activesupport (= 6.1.3.1)
|
|
34
|
+
rack (~> 2.0, >= 2.0.9)
|
|
33
35
|
rack-test (>= 0.6.3)
|
|
34
36
|
rails-dom-testing (~> 2.0)
|
|
35
37
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
|
36
|
-
actiontext (6.
|
|
37
|
-
actionpack (= 6.
|
|
38
|
-
activerecord (= 6.
|
|
39
|
-
activestorage (= 6.
|
|
40
|
-
activesupport (= 6.
|
|
38
|
+
actiontext (6.1.3.1)
|
|
39
|
+
actionpack (= 6.1.3.1)
|
|
40
|
+
activerecord (= 6.1.3.1)
|
|
41
|
+
activestorage (= 6.1.3.1)
|
|
42
|
+
activesupport (= 6.1.3.1)
|
|
41
43
|
nokogiri (>= 1.8.5)
|
|
42
|
-
actionview (6.
|
|
43
|
-
activesupport (= 6.
|
|
44
|
+
actionview (6.1.3.1)
|
|
45
|
+
activesupport (= 6.1.3.1)
|
|
44
46
|
builder (~> 3.1)
|
|
45
47
|
erubi (~> 1.4)
|
|
46
48
|
rails-dom-testing (~> 2.0)
|
|
47
49
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
|
48
|
-
activejob (6.
|
|
49
|
-
activesupport (= 6.
|
|
50
|
+
activejob (6.1.3.1)
|
|
51
|
+
activesupport (= 6.1.3.1)
|
|
50
52
|
globalid (>= 0.3.6)
|
|
51
|
-
activemodel (6.
|
|
52
|
-
activesupport (= 6.
|
|
53
|
-
activerecord (6.
|
|
54
|
-
activemodel (= 6.
|
|
55
|
-
activesupport (= 6.
|
|
56
|
-
activestorage (6.
|
|
57
|
-
actionpack (= 6.
|
|
58
|
-
activejob (= 6.
|
|
59
|
-
activerecord (= 6.
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
activemodel (6.1.3.1)
|
|
54
|
+
activesupport (= 6.1.3.1)
|
|
55
|
+
activerecord (6.1.3.1)
|
|
56
|
+
activemodel (= 6.1.3.1)
|
|
57
|
+
activesupport (= 6.1.3.1)
|
|
58
|
+
activestorage (6.1.3.1)
|
|
59
|
+
actionpack (= 6.1.3.1)
|
|
60
|
+
activejob (= 6.1.3.1)
|
|
61
|
+
activerecord (= 6.1.3.1)
|
|
62
|
+
activesupport (= 6.1.3.1)
|
|
63
|
+
marcel (~> 1.0.0)
|
|
64
|
+
mini_mime (~> 1.0.2)
|
|
65
|
+
activesupport (6.1.3.1)
|
|
62
66
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
63
|
-
i18n (>=
|
|
64
|
-
minitest (
|
|
65
|
-
tzinfo (~>
|
|
66
|
-
zeitwerk (~> 2.
|
|
67
|
+
i18n (>= 1.6, < 2)
|
|
68
|
+
minitest (>= 5.1)
|
|
69
|
+
tzinfo (~> 2.0)
|
|
70
|
+
zeitwerk (~> 2.3)
|
|
67
71
|
builder (3.2.4)
|
|
68
|
-
byebug (11.
|
|
72
|
+
byebug (11.1.1)
|
|
69
73
|
coderay (1.1.2)
|
|
70
|
-
concurrent-ruby (1.1.
|
|
71
|
-
crass (1.0.
|
|
74
|
+
concurrent-ruby (1.1.8)
|
|
75
|
+
crass (1.0.6)
|
|
72
76
|
diff-lcs (1.3)
|
|
73
|
-
erubi (1.
|
|
74
|
-
factory_bot (
|
|
75
|
-
activesupport (>=
|
|
76
|
-
factory_bot_rails (
|
|
77
|
-
factory_bot (~>
|
|
78
|
-
railties (>=
|
|
79
|
-
faker (2.
|
|
80
|
-
i18n (>= 1.6, <
|
|
81
|
-
fast_jsonapi (1.5)
|
|
82
|
-
activesupport (>= 4.2)
|
|
77
|
+
erubi (1.10.0)
|
|
78
|
+
factory_bot (6.1.0)
|
|
79
|
+
activesupport (>= 5.0.0)
|
|
80
|
+
factory_bot_rails (6.1.0)
|
|
81
|
+
factory_bot (~> 6.1.0)
|
|
82
|
+
railties (>= 5.0.0)
|
|
83
|
+
faker (2.10.2)
|
|
84
|
+
i18n (>= 1.6, < 2)
|
|
83
85
|
globalid (0.4.2)
|
|
84
86
|
activesupport (>= 4.2.0)
|
|
85
|
-
i18n (1.
|
|
87
|
+
i18n (1.8.10)
|
|
86
88
|
concurrent-ruby (~> 1.0)
|
|
87
|
-
|
|
89
|
+
jsonapi-serializer (2.2.0)
|
|
90
|
+
activesupport (>= 4.2)
|
|
91
|
+
loofah (2.9.1)
|
|
88
92
|
crass (~> 1.0.2)
|
|
89
93
|
nokogiri (>= 1.5.9)
|
|
90
94
|
mail (2.7.1)
|
|
91
95
|
mini_mime (>= 0.1.1)
|
|
92
|
-
marcel (0.
|
|
93
|
-
mimemagic (~> 0.3.2)
|
|
96
|
+
marcel (1.0.1)
|
|
94
97
|
method_source (0.9.2)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
mini_mime (1.0.3)
|
|
99
|
+
mini_portile2 (2.5.1)
|
|
100
|
+
minitest (5.14.4)
|
|
101
|
+
nio4r (2.5.7)
|
|
102
|
+
nokogiri (1.11.3)
|
|
103
|
+
mini_portile2 (~> 2.5.0)
|
|
104
|
+
racc (~> 1.4)
|
|
102
105
|
pry (0.12.2)
|
|
103
106
|
coderay (~> 1.1.0)
|
|
104
107
|
method_source (~> 0.9.0)
|
|
105
|
-
pry-byebug (3.
|
|
108
|
+
pry-byebug (3.8.0)
|
|
106
109
|
byebug (~> 11.0)
|
|
107
110
|
pry (~> 0.10)
|
|
108
|
-
|
|
111
|
+
racc (1.5.2)
|
|
112
|
+
rack (2.2.3)
|
|
109
113
|
rack-test (1.1.0)
|
|
110
114
|
rack (>= 1.0, < 3)
|
|
111
|
-
rails (6.
|
|
112
|
-
actioncable (= 6.
|
|
113
|
-
actionmailbox (= 6.
|
|
114
|
-
actionmailer (= 6.
|
|
115
|
-
actionpack (= 6.
|
|
116
|
-
actiontext (= 6.
|
|
117
|
-
actionview (= 6.
|
|
118
|
-
activejob (= 6.
|
|
119
|
-
activemodel (= 6.
|
|
120
|
-
activerecord (= 6.
|
|
121
|
-
activestorage (= 6.
|
|
122
|
-
activesupport (= 6.
|
|
123
|
-
bundler (>= 1.
|
|
124
|
-
railties (= 6.
|
|
115
|
+
rails (6.1.3.1)
|
|
116
|
+
actioncable (= 6.1.3.1)
|
|
117
|
+
actionmailbox (= 6.1.3.1)
|
|
118
|
+
actionmailer (= 6.1.3.1)
|
|
119
|
+
actionpack (= 6.1.3.1)
|
|
120
|
+
actiontext (= 6.1.3.1)
|
|
121
|
+
actionview (= 6.1.3.1)
|
|
122
|
+
activejob (= 6.1.3.1)
|
|
123
|
+
activemodel (= 6.1.3.1)
|
|
124
|
+
activerecord (= 6.1.3.1)
|
|
125
|
+
activestorage (= 6.1.3.1)
|
|
126
|
+
activesupport (= 6.1.3.1)
|
|
127
|
+
bundler (>= 1.15.0)
|
|
128
|
+
railties (= 6.1.3.1)
|
|
125
129
|
sprockets-rails (>= 2.0.0)
|
|
126
130
|
rails-controller-testing (1.0.4)
|
|
127
131
|
actionpack (>= 5.0.1.x)
|
|
@@ -132,19 +136,19 @@ GEM
|
|
|
132
136
|
nokogiri (>= 1.6)
|
|
133
137
|
rails-html-sanitizer (1.3.0)
|
|
134
138
|
loofah (~> 2.3)
|
|
135
|
-
railties (6.
|
|
136
|
-
actionpack (= 6.
|
|
137
|
-
activesupport (= 6.
|
|
139
|
+
railties (6.1.3.1)
|
|
140
|
+
actionpack (= 6.1.3.1)
|
|
141
|
+
activesupport (= 6.1.3.1)
|
|
138
142
|
method_source
|
|
139
143
|
rake (>= 0.8.7)
|
|
140
|
-
thor (
|
|
141
|
-
rake (
|
|
142
|
-
rspec-core (3.9.
|
|
143
|
-
rspec-support (~> 3.9.
|
|
144
|
+
thor (~> 1.0)
|
|
145
|
+
rake (13.0.3)
|
|
146
|
+
rspec-core (3.9.1)
|
|
147
|
+
rspec-support (~> 3.9.1)
|
|
144
148
|
rspec-expectations (3.9.0)
|
|
145
149
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
146
150
|
rspec-support (~> 3.9.0)
|
|
147
|
-
rspec-mocks (3.9.
|
|
151
|
+
rspec-mocks (3.9.1)
|
|
148
152
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
149
153
|
rspec-support (~> 3.9.0)
|
|
150
154
|
rspec-rails (3.9.0)
|
|
@@ -155,23 +159,22 @@ GEM
|
|
|
155
159
|
rspec-expectations (~> 3.9.0)
|
|
156
160
|
rspec-mocks (~> 3.9.0)
|
|
157
161
|
rspec-support (~> 3.9.0)
|
|
158
|
-
rspec-support (3.9.
|
|
159
|
-
sprockets (4.0.
|
|
162
|
+
rspec-support (3.9.2)
|
|
163
|
+
sprockets (4.0.2)
|
|
160
164
|
concurrent-ruby (~> 1.0)
|
|
161
165
|
rack (> 1, < 3)
|
|
162
|
-
sprockets-rails (3.2.
|
|
166
|
+
sprockets-rails (3.2.2)
|
|
163
167
|
actionpack (>= 4.0)
|
|
164
168
|
activesupport (>= 4.0)
|
|
165
169
|
sprockets (>= 3.0.0)
|
|
166
170
|
sqlite3 (1.4.2)
|
|
167
|
-
thor (1.0
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
websocket-driver (0.7.1)
|
|
171
|
+
thor (1.1.0)
|
|
172
|
+
tzinfo (2.0.4)
|
|
173
|
+
concurrent-ruby (~> 1.0)
|
|
174
|
+
websocket-driver (0.7.3)
|
|
172
175
|
websocket-extensions (>= 0.1.0)
|
|
173
|
-
websocket-extensions (0.1.
|
|
174
|
-
zeitwerk (2.
|
|
176
|
+
websocket-extensions (0.1.5)
|
|
177
|
+
zeitwerk (2.4.2)
|
|
175
178
|
|
|
176
179
|
PLATFORMS
|
|
177
180
|
ruby
|
|
@@ -185,9 +188,9 @@ DEPENDENCIES
|
|
|
185
188
|
pry-byebug
|
|
186
189
|
rails
|
|
187
190
|
rails-controller-testing
|
|
188
|
-
rake (~>
|
|
191
|
+
rake (~> 13.0)
|
|
189
192
|
rspec-rails (~> 3.9)
|
|
190
193
|
sqlite3
|
|
191
194
|
|
|
192
195
|
BUNDLED WITH
|
|
193
|
-
2.1.
|
|
196
|
+
2.1.4
|
data/README.md
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# JsonApiable
|
|
2
|
+
[](https://codeclimate.com/github/mikemarsian/json_apiable/maintainability)
|
|
3
|
+
[](https://badge.fury.io/rb/json_apiable)
|
|
2
4
|
|
|
3
5
|
JsonApiable is a Ruby module that makes it easier for Rails API controllers to handle JSON:API parameter and relationship parsing,
|
|
4
6
|
strong parameter validation, returning well-structured errors and more - all in a Rails-friendly way.
|
|
@@ -54,7 +56,7 @@ class API::PostsController < API::BaseController
|
|
|
54
56
|
# GET /v1/posts
|
|
55
57
|
def index
|
|
56
58
|
# pass page and include info to your logic
|
|
57
|
-
posts = GetPostsService.call(
|
|
59
|
+
posts = GetPostsService.call(jsonapi_page_hash, jsonapi_include_array)
|
|
58
60
|
# some other gem, such as fast_jsonapi is assumed to produce the json:api output
|
|
59
61
|
render json: posts
|
|
60
62
|
end
|
|
@@ -97,7 +99,7 @@ class API::PostsController < API::BaseController
|
|
|
97
99
|
#
|
|
98
100
|
# }
|
|
99
101
|
@post.update_attributes!(jsonapi_assign_params)
|
|
100
|
-
render json: @
|
|
102
|
+
render json: @post
|
|
101
103
|
end
|
|
102
104
|
|
|
103
105
|
def create
|
|
@@ -111,7 +113,7 @@ class API::PostsController < API::BaseController
|
|
|
111
113
|
@comments_hash = jsonapi_exclude_relationship(:comments)
|
|
112
114
|
do_some_logc_with_excluded_params
|
|
113
115
|
# jsonapi_assign_params wouldn't include 'author' attribute and 'comments' relationship
|
|
114
|
-
|
|
116
|
+
Post.create!(jsonapi_assign_params)
|
|
115
117
|
end
|
|
116
118
|
|
|
117
119
|
protected
|
|
@@ -132,6 +134,76 @@ class API::PostsController < API::BaseController
|
|
|
132
134
|
|
|
133
135
|
end
|
|
134
136
|
````
|
|
137
|
+
### Filters
|
|
138
|
+
JsonApiable supports parsing filter requests in the form `example.com/v1/posts?filter[status]=draft` and returning errors
|
|
139
|
+
in case provided filter keys or values do not adhere to what you define:
|
|
140
|
+
|
|
141
|
+
```ruby
|
|
142
|
+
# Create filter class that inherits from JsonApiable::BaseFilter
|
|
143
|
+
class API::PostFilter < JsonApiable::BaseFilter
|
|
144
|
+
# Declare which filter keys are supported
|
|
145
|
+
def self.jsonapi_allowed_filters
|
|
146
|
+
{
|
|
147
|
+
# For each key, declare what values are allowed. The supported value matchers include:
|
|
148
|
+
# 1) Array of values
|
|
149
|
+
# example.com/v1/posts?filter[status]=draft,published
|
|
150
|
+
status: Post.statuses.keys,
|
|
151
|
+
|
|
152
|
+
# 2) DateTime matcher - proc that checks that the provided value is a valid DateTime
|
|
153
|
+
# example.com/v1/posts?filter[published_at]='2001-02-03T04:05:06+03:00'
|
|
154
|
+
published_at: datetime_matcher,
|
|
155
|
+
|
|
156
|
+
# 3) Boolean matcher - proc that checks that the provided value is a boolean (true/t/1 for True, false/f/0 for False)
|
|
157
|
+
# example.com/v1/posts?filter[subscribers_only]=true
|
|
158
|
+
subscribers_only: boolean_matcher,
|
|
159
|
+
|
|
160
|
+
# 4) ID matcher - proc that checks that the provided ids exist for given model
|
|
161
|
+
# example.com/v1/posts?filter[ids]=10893,14596
|
|
162
|
+
ids: ids_matcher(Post),
|
|
163
|
+
|
|
164
|
+
# Of course, you can also implement your own matchers. For example:
|
|
165
|
+
reviewed_at: recent_datetime_matcher
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Example of custom filter value matcher
|
|
170
|
+
def self.recent_datetime_matcher
|
|
171
|
+
proc do |value|
|
|
172
|
+
datetime = Time.zone.parse(value)
|
|
173
|
+
datetime.present? && datetime > 10.years.ago && datetime < 2.years.from_now
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
Now set the filter for actions which should support filtering:
|
|
179
|
+
```ruby
|
|
180
|
+
class API::PostsController < API::BaseController
|
|
181
|
+
before_action -> { set_jsonapi_filter(API::PostFilter) }, only: %i[index search]
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
And you are good to go!
|
|
186
|
+
|
|
187
|
+
Incidentally, PostFilter class is also a good place to implement your filter logic:
|
|
188
|
+
```ruby
|
|
189
|
+
class API::PostFilter < JsonApiable::BaseFilter
|
|
190
|
+
# The following methods are available to a filter class instance:
|
|
191
|
+
# jsonapi_collection - collection on which to execute filtering
|
|
192
|
+
# jsonapi_filter_hash - a filter query hash, e.g. { 'status' => ['draft', 'published'], 'published_at' => '2001-02-03T04:05:06+03:00' }
|
|
193
|
+
def call
|
|
194
|
+
jsonapi_collection.where(status: jsonapi_filter_hash[:status])
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
Now you can call filter posts collection in your controller:
|
|
199
|
+
```ruby
|
|
200
|
+
posts = GetPosts.call
|
|
201
|
+
# jsonapi_filter_class - API::PostFilter in our example
|
|
202
|
+
# jsonapi_filter_hash - a filter query hash, e.g. { 'status' => ['draft', 'published'] }
|
|
203
|
+
filtered_posts = jsonapi_filter_class.new(posts, jsonapi_filter_hash).call
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
|
|
135
207
|
### Configuration
|
|
136
208
|
Add an initializer to your app with the following config block:
|
|
137
209
|
```ruby
|
data/json_apiable.gemspec
CHANGED
|
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
25
25
|
spec.require_paths = ["lib"]
|
|
26
26
|
|
|
27
|
-
spec.add_dependency 'activerecord'
|
|
28
|
-
spec.add_dependency 'activesupport'
|
|
29
|
-
spec.add_dependency '
|
|
27
|
+
spec.add_dependency 'activerecord'
|
|
28
|
+
spec.add_dependency 'activesupport'
|
|
29
|
+
spec.add_dependency 'jsonapi-serializer'
|
|
30
30
|
|
|
31
31
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
|
32
32
|
spec.add_development_dependency 'factory_bot_rails'
|
|
@@ -35,7 +35,7 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.add_development_dependency 'pry-byebug'
|
|
36
36
|
spec.add_development_dependency 'rails'
|
|
37
37
|
spec.add_development_dependency 'rails-controller-testing'
|
|
38
|
-
spec.add_development_dependency 'rake', '~>
|
|
38
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
|
39
39
|
spec.add_development_dependency 'rspec-rails', '~> 3.9'
|
|
40
40
|
spec.add_development_dependency 'sqlite3'
|
|
41
41
|
end
|
data/lib/json_apiable.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'active_support/all'
|
|
2
4
|
require "json_apiable/version"
|
|
3
5
|
require "json_apiable/core_extensions"
|
|
@@ -6,7 +8,10 @@ require 'json_apiable/renderers'
|
|
|
6
8
|
require 'json_apiable/errors'
|
|
7
9
|
require 'json_apiable/params_parser'
|
|
8
10
|
require 'json_apiable/pagination_parser'
|
|
11
|
+
require 'json_apiable/filter_parser'
|
|
12
|
+
require 'json_apiable/filter_matchers'
|
|
13
|
+
require 'json_apiable/base_filter'
|
|
9
14
|
require 'json_apiable/json_apiable'
|
|
10
15
|
|
|
11
16
|
String.include CoreExtensions::String
|
|
12
|
-
Mime::Type.register JsonApiable::JSONAPI_CONTENT_TYPE, :json_api
|
|
17
|
+
Mime::Type.register JsonApiable::JSONAPI_CONTENT_TYPE, :json_api
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JsonApiable
|
|
4
|
+
# Base class for Filters
|
|
5
|
+
class BaseFilter
|
|
6
|
+
extend JsonApiable::FilterMatchers
|
|
7
|
+
|
|
8
|
+
attr_reader :jsonapi_collection, :jsonapi_filter_hash, :current_user
|
|
9
|
+
|
|
10
|
+
protected
|
|
11
|
+
|
|
12
|
+
def initialize(a_collection, a_filter_hash, current_user)
|
|
13
|
+
@jsonapi_collection = a_collection
|
|
14
|
+
@jsonapi_filter_hash = a_filter_hash
|
|
15
|
+
@current_user = current_user
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def jsonapi_allowed_filters
|
|
20
|
+
{}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module JsonApiable
|
|
2
4
|
class Configuration
|
|
3
5
|
attr_accessor :valid_query_params, :supported_media_type_proc, :not_found_exception_class, :page_size
|
|
@@ -29,4 +31,4 @@ module JsonApiable
|
|
|
29
31
|
@not_found_exception_class = klass
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
|
-
end
|
|
34
|
+
end
|
data/lib/json_apiable/errors.rb
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JsonApiable
|
|
4
|
+
module FilterMatchers
|
|
5
|
+
def matches?(allowed, given)
|
|
6
|
+
given.all? do |value|
|
|
7
|
+
allowed.is_a?(Proc) ? allowed.call(value) : allowed.include?(value)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module_function :matches?
|
|
12
|
+
|
|
13
|
+
# returns true for boolean values, false for any other
|
|
14
|
+
def boolean_matcher
|
|
15
|
+
proc do |value|
|
|
16
|
+
handle_error(value) do
|
|
17
|
+
if true_matcher.call(value) || (value == false || value =~ /^(false|f|0)$/i)
|
|
18
|
+
true
|
|
19
|
+
else
|
|
20
|
+
false
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# returns true for true values, false for any other
|
|
27
|
+
def true_matcher
|
|
28
|
+
proc do |value|
|
|
29
|
+
handle_error(value) do
|
|
30
|
+
if value == true || value =~ /^(true|t|1)$/i
|
|
31
|
+
true
|
|
32
|
+
else
|
|
33
|
+
false
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# returns true if the value is a valid date or datetime
|
|
40
|
+
def datetime_matcher
|
|
41
|
+
proc do |value|
|
|
42
|
+
handle_error(value) do
|
|
43
|
+
datetime = value.in_time_zone(Time.zone)
|
|
44
|
+
datetime.present?
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# returns true if the value is a an array of existing ids of the given model
|
|
50
|
+
def ids_matcher(model)
|
|
51
|
+
proc do |value|
|
|
52
|
+
handle_error(value) do
|
|
53
|
+
given_ids = value.split(',')
|
|
54
|
+
found_records = model.where(id: given_ids)
|
|
55
|
+
|
|
56
|
+
given_ids.count == found_records.count
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def handle_error(value)
|
|
62
|
+
yield
|
|
63
|
+
rescue ArgumentError => e
|
|
64
|
+
raise ArgumentError, "#{value}: #{e.message}"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JsonApiable
|
|
4
|
+
class FilterParser
|
|
5
|
+
def self.parse_filters!(jsonapi_build_params, filter_class)
|
|
6
|
+
FilterParser.new(jsonapi_build_params[:filter], filter_class).parse!
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
attr_reader :filter_param, :filter_class
|
|
10
|
+
|
|
11
|
+
def initialize(filter_param, filter_class)
|
|
12
|
+
@filter_param = filter_param
|
|
13
|
+
@filter_class = filter_class
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Support filtering in the form of example.com/v1/posts?filter[status]=draft,published
|
|
17
|
+
def parse!
|
|
18
|
+
raise_invalid_filter_class unless valid_filter_class?
|
|
19
|
+
|
|
20
|
+
filter_hash = ActiveSupport::HashWithIndifferentAccess.new
|
|
21
|
+
if valid_filter_query?
|
|
22
|
+
filter_param.keys.each do |k|
|
|
23
|
+
if valid_filter_key?(k)
|
|
24
|
+
# support notation ?filter[param]=value1,value2,value3&...
|
|
25
|
+
requested = filter_param[k].split(',')
|
|
26
|
+
allowed_values = allowed_filter_keys[k]
|
|
27
|
+
raise_invalid_filter_value(k) unless FilterMatchers.matches?(allowed_values, requested)
|
|
28
|
+
|
|
29
|
+
filter_hash[k] = requested
|
|
30
|
+
else
|
|
31
|
+
raise_invalid_filter_value(k)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
elsif filter_param.present?
|
|
35
|
+
raise ArgumentError, 'filter'
|
|
36
|
+
end
|
|
37
|
+
filter_hash
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def raise_argument_error(message)
|
|
43
|
+
raise ArgumentError, message
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def raise_invalid_filter_value(k)
|
|
47
|
+
prefix = "filter[#{k}]"
|
|
48
|
+
msg = filter_param[k].present? ? "#{prefix}=#{filter_param[k]}" : prefix
|
|
49
|
+
raise_argument_error(msg)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def raise_invalid_filter_class
|
|
53
|
+
raise_argument_error("#{filter_class} does not specify jsonapi_allowed_filters")
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def valid_filter_class?
|
|
57
|
+
filter_class.respond_to?(:jsonapi_allowed_filters)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def valid_filter_query?
|
|
61
|
+
filter_param.present? && (filter_param.is_a?(Hash) || filter_param.is_a?(ActionController::Parameters))
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def valid_filter_key?(k)
|
|
65
|
+
allowed_filter_keys.key?(k) && filter_param[k].present?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def allowed_filter_keys
|
|
69
|
+
filter_class.jsonapi_allowed_filters.with_indifferent_access
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module JsonApiable
|
|
2
4
|
extend ActiveSupport::Concern
|
|
3
5
|
include Errors
|
|
@@ -5,8 +7,8 @@ module JsonApiable
|
|
|
5
7
|
|
|
6
8
|
JSONAPI_CONTENT_TYPE = 'application/vnd.api+json'
|
|
7
9
|
|
|
8
|
-
attr_reader :
|
|
9
|
-
:jsonapi_exclude_attributes, :jsonapi_exclude_relationships
|
|
10
|
+
attr_reader :jsonapi_page_hash, :jsonapi_include_array, :jsonapi_filter_hash, :jsonapi_filter_class, :jsonapi_build_params,
|
|
11
|
+
:jsonapi_assign_params, :jsonapi_default_page_size, :jsonapi_exclude_attributes, :jsonapi_exclude_relationships
|
|
10
12
|
|
|
11
13
|
included do
|
|
12
14
|
before_action :ensure_jsonapi_content_type
|
|
@@ -18,6 +20,7 @@ module JsonApiable
|
|
|
18
20
|
|
|
19
21
|
rescue_from ArgumentError, with: :respond_to_bad_argument
|
|
20
22
|
rescue_from ActionController::UnpermittedParameters, with: :respond_to_bad_argument
|
|
23
|
+
rescue_from JSONAPI::Serializer::UnsupportedIncludeError, with: :respond_to_exception_raised
|
|
21
24
|
rescue_from MalformedRequestError, with: :respond_to_malformed_request
|
|
22
25
|
rescue_from UnprocessableEntityError, with: :respond_to_unprocessable_entity
|
|
23
26
|
rescue_from UnauthorizedError, with: :respond_to_unauthorized
|
|
@@ -25,7 +28,6 @@ module JsonApiable
|
|
|
25
28
|
rescue_from JsonApiable.configuration.not_found_exception_class, with: :respond_to_not_found
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
|
|
29
31
|
class << self
|
|
30
32
|
attr_writer :configuration
|
|
31
33
|
end
|
|
@@ -63,28 +65,37 @@ module JsonApiable
|
|
|
63
65
|
end
|
|
64
66
|
|
|
65
67
|
def jsonapi_relationship_attribute(relationship, attribute)
|
|
66
|
-
[:id, :type].include?(attribute.to_sym)
|
|
67
|
-
|
|
68
|
+
if [:id, :type].include?(attribute.to_sym)
|
|
69
|
+
jsonapi_relationship_data(relationship)&.dig(attribute)
|
|
70
|
+
else
|
|
71
|
+
jsonapi_relationship_data(relationship)&.dig(:attributes, attribute)
|
|
72
|
+
end
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
def jsonapi_assign_params
|
|
71
|
-
@jsonapi_assign_params
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
return @jsonapi_assign_params if @jsonapi_assign_params.present? && !@invalidate_assign_params
|
|
77
|
+
|
|
78
|
+
@jsonapi_assign_params = ParamsParser.parse_body_params(request,
|
|
79
|
+
jsonapi_build_params,
|
|
80
|
+
jsonapi_allowed_attributes,
|
|
81
|
+
jsonapi_exclude_attributes,
|
|
82
|
+
jsonapi_allowed_relationships,
|
|
83
|
+
jsonapi_exclude_relationships)
|
|
84
|
+
@invalidate_assign_params = false
|
|
85
|
+
@jsonapi_assign_params
|
|
77
86
|
end
|
|
78
87
|
|
|
79
88
|
def jsonapi_exclude_attribute(attrib_key)
|
|
80
89
|
@jsonapi_exclude_attributes ||= []
|
|
81
90
|
@jsonapi_exclude_attributes << attrib_key.to_sym
|
|
91
|
+
@invalidate_assign_params = true
|
|
82
92
|
jsonapi_build_params.dig(:data, :attributes, attrib_key)
|
|
83
93
|
end
|
|
84
94
|
|
|
85
95
|
def jsonapi_exclude_relationship(rel_key)
|
|
86
96
|
@jsonapi_exclude_relationships ||= []
|
|
87
97
|
@jsonapi_exclude_relationships << rel_key.to_sym
|
|
98
|
+
@invalidate_assign_params = true
|
|
88
99
|
jsonapi_build_params.dig(:data, :relationships, rel_key)
|
|
89
100
|
end
|
|
90
101
|
|
|
@@ -126,19 +137,24 @@ module JsonApiable
|
|
|
126
137
|
end
|
|
127
138
|
end
|
|
128
139
|
|
|
140
|
+
def set_jsonapi_filter(filter_class)
|
|
141
|
+
@jsonapi_filter_class = filter_class
|
|
142
|
+
@jsonapi_filter_hash = FilterParser.parse_filters!(jsonapi_build_params, filter_class)
|
|
143
|
+
end
|
|
144
|
+
|
|
129
145
|
def set_jsonapi_content_type
|
|
130
146
|
response.headers['Content-Type'] = JSONAPI_CONTENT_TYPE
|
|
131
147
|
end
|
|
132
148
|
|
|
133
149
|
def parse_jsonapi_pagination
|
|
134
|
-
@
|
|
150
|
+
@jsonapi_page_hash = PaginationParser.parse_pagination!(query_params, jsonapi_default_page_size)
|
|
135
151
|
end
|
|
136
152
|
|
|
137
153
|
def parse_jsonapi_include
|
|
138
|
-
@
|
|
154
|
+
@jsonapi_include_array = query_params[:include].presence&.gsub(/ /, '')&.split(',')&.map(&:to_sym).to_a
|
|
139
155
|
end
|
|
140
156
|
|
|
141
157
|
def query_params
|
|
142
158
|
request.query_parameters
|
|
143
159
|
end
|
|
144
|
-
end
|
|
160
|
+
end
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module JsonApiable
|
|
2
4
|
class PaginationParser
|
|
3
|
-
|
|
4
5
|
def self.parse_pagination!(query_params, default_page_size)
|
|
5
6
|
PaginationParser.new(query_params[:page], query_params[:no_pagination], default_page_size).parse!
|
|
6
7
|
end
|
|
@@ -15,7 +16,7 @@ module JsonApiable
|
|
|
15
16
|
|
|
16
17
|
def parse!
|
|
17
18
|
if no_pagination
|
|
18
|
-
|
|
19
|
+
jsonapi_page_hash = nil
|
|
19
20
|
elsif invalid_page_param?
|
|
20
21
|
raise ArgumentError, 'page'
|
|
21
22
|
elsif invalid_page_number?
|
|
@@ -23,14 +24,14 @@ module JsonApiable
|
|
|
23
24
|
elsif invalid_page_size?
|
|
24
25
|
raise ArgumentError, 'page[size]'
|
|
25
26
|
else
|
|
26
|
-
|
|
27
|
+
jsonapi_page_hash = page_param.presence.to_h.with_indifferent_access
|
|
27
28
|
# convert values to integers
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
jsonapi_page_hash = jsonapi_page_hash.merge(jsonapi_page_hash) { |_, v| v.to_i } if jsonapi_page_hash.present?
|
|
30
|
+
jsonapi_page_hash = { number: Configuration::DEFAULT_PAGE_NUMBER, size: default_page_size } if jsonapi_page_hash.blank?
|
|
31
|
+
jsonapi_page_hash[:number] = Configuration::DEFAULT_PAGE_NUMBER if jsonapi_page_hash[:number].blank?
|
|
32
|
+
jsonapi_page_hash[:size] = default_page_size if jsonapi_page_hash[:size].blank?
|
|
32
33
|
end
|
|
33
|
-
|
|
34
|
+
jsonapi_page_hash
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
private
|
|
@@ -56,4 +57,4 @@ module JsonApiable
|
|
|
56
57
|
number > Configuration::MAX_PAGE_SIZE || number.zero? || number.negative?
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
|
-
end
|
|
60
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module JsonApiable
|
|
2
4
|
class ParamsParser
|
|
3
5
|
class DataParams
|
|
@@ -39,7 +41,9 @@ module JsonApiable
|
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def self.build_relationships_hash(relationships, excluded_relationships, request)
|
|
42
|
-
attr_hash = {}
|
|
44
|
+
attr_hash = {}
|
|
45
|
+
ids_array = []
|
|
46
|
+
ids_key = nil
|
|
43
47
|
|
|
44
48
|
relationships&.each_pair do |key, data_hash|
|
|
45
49
|
next if excluded_relationships&.include?(key.to_sym)
|
|
@@ -72,7 +76,7 @@ module JsonApiable
|
|
|
72
76
|
end
|
|
73
77
|
|
|
74
78
|
def self.hashify(allowed_relationships)
|
|
75
|
-
allowed_relationships.map{|rel| { rel => {}}}
|
|
79
|
+
allowed_relationships.map { |rel| { rel => {} } }
|
|
76
80
|
end
|
|
77
81
|
end
|
|
78
|
-
end
|
|
82
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module JsonApiable
|
|
2
4
|
module Renderers
|
|
3
5
|
def respond_to_unsupported_media_type
|
|
@@ -30,6 +32,11 @@ module JsonApiable
|
|
|
30
32
|
json_render_errors json: errors, status: :bad_request
|
|
31
33
|
end
|
|
32
34
|
|
|
35
|
+
def respond_to_exception_raised(err_msg)
|
|
36
|
+
errors = [{ title: 'Invalid Argument', detail: err_msg.message }]
|
|
37
|
+
json_render_errors json: errors, status: :bad_request
|
|
38
|
+
end
|
|
39
|
+
|
|
33
40
|
def respond_to_malformed_request(err_msg = nil)
|
|
34
41
|
errors = [{ title: 'Malformed Request', detail: err_msg.to_s }]
|
|
35
42
|
json_render_errors json: errors, status: :bad_request
|
|
@@ -49,4 +56,4 @@ module JsonApiable
|
|
|
49
56
|
render json: { errors: json }, status: status
|
|
50
57
|
end
|
|
51
58
|
end
|
|
52
|
-
end
|
|
59
|
+
end
|
data/lib/json_apiable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json_apiable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 0.5.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mike Polischuk
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -16,42 +16,42 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: activesupport
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '0'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
42
|
+
name: jsonapi-serializer
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
|
-
- - "
|
|
45
|
+
- - ">="
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '0'
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
|
-
- - "
|
|
52
|
+
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: bundler
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -156,14 +156,14 @@ dependencies:
|
|
|
156
156
|
requirements:
|
|
157
157
|
- - "~>"
|
|
158
158
|
- !ruby/object:Gem::Version
|
|
159
|
-
version: '
|
|
159
|
+
version: '13.0'
|
|
160
160
|
type: :development
|
|
161
161
|
prerelease: false
|
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
|
163
163
|
requirements:
|
|
164
164
|
- - "~>"
|
|
165
165
|
- !ruby/object:Gem::Version
|
|
166
|
-
version: '
|
|
166
|
+
version: '13.0'
|
|
167
167
|
- !ruby/object:Gem::Dependency
|
|
168
168
|
name: rspec-rails
|
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -192,7 +192,7 @@ dependencies:
|
|
|
192
192
|
- - ">="
|
|
193
193
|
- !ruby/object:Gem::Version
|
|
194
194
|
version: '0'
|
|
195
|
-
description:
|
|
195
|
+
description:
|
|
196
196
|
email:
|
|
197
197
|
- mike.polis@gmail.com
|
|
198
198
|
executables: []
|
|
@@ -201,6 +201,7 @@ extra_rdoc_files: []
|
|
|
201
201
|
files:
|
|
202
202
|
- ".gitignore"
|
|
203
203
|
- ".rspec"
|
|
204
|
+
- ".rubocop.yml"
|
|
204
205
|
- ".travis.yml"
|
|
205
206
|
- Gemfile
|
|
206
207
|
- Gemfile.lock
|
|
@@ -211,9 +212,12 @@ files:
|
|
|
211
212
|
- bin/setup
|
|
212
213
|
- json_apiable.gemspec
|
|
213
214
|
- lib/json_apiable.rb
|
|
215
|
+
- lib/json_apiable/base_filter.rb
|
|
214
216
|
- lib/json_apiable/configuration.rb
|
|
215
217
|
- lib/json_apiable/core_extensions.rb
|
|
216
218
|
- lib/json_apiable/errors.rb
|
|
219
|
+
- lib/json_apiable/filter_matchers.rb
|
|
220
|
+
- lib/json_apiable/filter_parser.rb
|
|
217
221
|
- lib/json_apiable/json_apiable.rb
|
|
218
222
|
- lib/json_apiable/pagination_parser.rb
|
|
219
223
|
- lib/json_apiable/params_parser.rb
|
|
@@ -224,7 +228,7 @@ licenses:
|
|
|
224
228
|
- MIT
|
|
225
229
|
metadata:
|
|
226
230
|
homepage_uri: http://github.com/mikemarsian/json_apiable
|
|
227
|
-
post_install_message:
|
|
231
|
+
post_install_message:
|
|
228
232
|
rdoc_options: []
|
|
229
233
|
require_paths:
|
|
230
234
|
- lib
|
|
@@ -239,8 +243,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
239
243
|
- !ruby/object:Gem::Version
|
|
240
244
|
version: '0'
|
|
241
245
|
requirements: []
|
|
242
|
-
rubygems_version: 3.
|
|
243
|
-
signing_key:
|
|
246
|
+
rubygems_version: 3.1.4
|
|
247
|
+
signing_key:
|
|
244
248
|
specification_version: 4
|
|
245
249
|
summary: Include JsonApiable module in your API::BaseController to receive a collection
|
|
246
250
|
of useful methods, such as arguments and relationships parser, filters, etc.
|