jsonapi_parameters 0.2.0 → 0.3.0
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/README.md +207 -0
- data/Rakefile +2 -9
- data/lib/jsonapi_parameters.rb +2 -0
- data/lib/jsonapi_parameters/core_ext.rb +2 -2
- data/lib/jsonapi_parameters/translator.rb +31 -9
- data/lib/jsonapi_parameters/version.rb +4 -2
- metadata +30 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02a88091cd1b68f0f385e97308b9b5ed213fe640f5f4831d0e83227cbb24fc98
|
4
|
+
data.tar.gz: 56dc70b94dac08359d21703245e1f5a8b7864bf9a0ec4b487b68057121fcac60
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b2ec520d45378a5c44c59f6eb37fd2d809e200eb0203d200d3b388a94dbfacfe0dfab9c1578f5ea446aba52de63deeb618e7baf9263c38573ac406cdedadf9bf
|
7
|
+
data.tar.gz: e9a193c2d58b04be662ae0481d9dc1ff451dbd49b44f7d4b18f0698b99c1958e843c66cb8659bf304db8ed649ac996643738dc6041f466ebc15492f2b330d5cf
|
data/README.md
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# JsonApi::Parameters
|
2
2
|
Simple JSON:API compliant parameters translator.
|
3
3
|
|
4
|
+
[](https://badge.fury.io/rb/jsonapi_parameters)
|
5
|
+
[](https://codeclimate.com/github/visualitypl/jsonapi_parameters/maintainability)
|
6
|
+
[](https://codeclimate.com/github/visualitypl/jsonapi_parameters/test_coverage)
|
7
|
+
|
4
8
|
#### The problem
|
5
9
|
|
6
10
|
JSON:API standard specifies not only responses (that can be handled nicely, using gems like [fast_jsonapi from Netflix](https://github.com/Netflix/fast_jsonapi)), but also the request structure.
|
@@ -60,6 +64,209 @@ def create_params
|
|
60
64
|
end
|
61
65
|
```
|
62
66
|
|
67
|
+
#### Relationships
|
68
|
+
|
69
|
+
JsonApi::Parameters supports ActiveRecord relationship parameters, including [nested attributes](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html).
|
70
|
+
|
71
|
+
Relationship parameters are being read from two optional trees:
|
72
|
+
|
73
|
+
* `relationships`,
|
74
|
+
* `included`
|
75
|
+
|
76
|
+
If you provide any related resources in the `relationships` table, this gem will also look for corresponding, `included` resources and their attributes. Thanks to that this gem supports nested attributes, and will try to translate these included resources and pass them along.
|
77
|
+
|
78
|
+
##### belongs_to
|
79
|
+
|
80
|
+
Passing a resource that is a single entity in relationships tree will make JsonApi::Parameters assume that it is a `belongs_to` relationship.
|
81
|
+
|
82
|
+
###### Without included entity
|
83
|
+
Example:
|
84
|
+
|
85
|
+
```
|
86
|
+
class Movie < ActiveRecord::Model
|
87
|
+
belongs_to :director
|
88
|
+
end
|
89
|
+
```
|
90
|
+
|
91
|
+
Request body:
|
92
|
+
|
93
|
+
```
|
94
|
+
{
|
95
|
+
data: {
|
96
|
+
type: 'movies',
|
97
|
+
attributes: {
|
98
|
+
title: 'The Terminator',
|
99
|
+
},
|
100
|
+
relationships: {
|
101
|
+
director: {
|
102
|
+
data: {
|
103
|
+
id: 682, type: 'directors'
|
104
|
+
}
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
}
|
109
|
+
```
|
110
|
+
|
111
|
+
Will translate to:
|
112
|
+
|
113
|
+
```
|
114
|
+
{
|
115
|
+
movie: {
|
116
|
+
title: 'The Terminator',
|
117
|
+
director_id: 682
|
118
|
+
}
|
119
|
+
}
|
120
|
+
```
|
121
|
+
|
122
|
+
|
123
|
+
###### With included entity:
|
124
|
+
Example:
|
125
|
+
|
126
|
+
```
|
127
|
+
class Movie < ActiveRecord::Model
|
128
|
+
belongs_to :director
|
129
|
+
|
130
|
+
accepts_nested_attributes_for :director
|
131
|
+
end
|
132
|
+
```
|
133
|
+
|
134
|
+
Request body:
|
135
|
+
```
|
136
|
+
{
|
137
|
+
data: {
|
138
|
+
type: 'movies',
|
139
|
+
attributes: {
|
140
|
+
title: 'The Terminator',
|
141
|
+
},
|
142
|
+
relationships: {
|
143
|
+
director: {
|
144
|
+
data: {
|
145
|
+
id: 682, type: 'directors'
|
146
|
+
}
|
147
|
+
}
|
148
|
+
}
|
149
|
+
},
|
150
|
+
included: [
|
151
|
+
{
|
152
|
+
type: 'directors',
|
153
|
+
id: 682,
|
154
|
+
attributes: {
|
155
|
+
name: 'Some guy'
|
156
|
+
}
|
157
|
+
}
|
158
|
+
]
|
159
|
+
}
|
160
|
+
```
|
161
|
+
|
162
|
+
Will translate to:
|
163
|
+
```
|
164
|
+
{
|
165
|
+
movie: {
|
166
|
+
title: 'The Terminator',
|
167
|
+
director_attributes: { id: 682, name: 'Some guy' }
|
168
|
+
}
|
169
|
+
}
|
170
|
+
```
|
171
|
+
|
172
|
+
##### has_many
|
173
|
+
|
174
|
+
Passing a resource that is a an array of entities in relationships tree will make JsonApi::Parameters assume that it is a `has_many` relationship.
|
175
|
+
|
176
|
+
###### Without included entity
|
177
|
+
Example:
|
178
|
+
|
179
|
+
```
|
180
|
+
class Movie < ActiveRecord::Model
|
181
|
+
has_many :genres
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
Request body:
|
186
|
+
|
187
|
+
```
|
188
|
+
{
|
189
|
+
data: {
|
190
|
+
type: 'movies',
|
191
|
+
attributes: {
|
192
|
+
title: 'The Terminator',
|
193
|
+
},
|
194
|
+
relationships: {
|
195
|
+
genres: [{
|
196
|
+
data: {
|
197
|
+
id: 1, type: 'genres'
|
198
|
+
},
|
199
|
+
data: {
|
200
|
+
id: 2, type: 'genres'
|
201
|
+
},
|
202
|
+
}]
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
```
|
207
|
+
|
208
|
+
Will translate to:
|
209
|
+
|
210
|
+
```
|
211
|
+
{
|
212
|
+
movie: {
|
213
|
+
title: 'The Terminator',
|
214
|
+
genre_ids: [1, 2]
|
215
|
+
}
|
216
|
+
}
|
217
|
+
```
|
218
|
+
|
219
|
+
|
220
|
+
###### With included entity:
|
221
|
+
Example:
|
222
|
+
|
223
|
+
```
|
224
|
+
class Movie < ActiveRecord::Model
|
225
|
+
has_many :genres
|
226
|
+
|
227
|
+
accepts_nested_attributes_for :genres
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
Request body:
|
232
|
+
```
|
233
|
+
{
|
234
|
+
data: {
|
235
|
+
type: 'movies',
|
236
|
+
attributes: {
|
237
|
+
title: 'The Terminator',
|
238
|
+
},
|
239
|
+
relationships: {
|
240
|
+
genres: [{
|
241
|
+
data: {
|
242
|
+
id: 1, type: 'genres'
|
243
|
+
}
|
244
|
+
}]
|
245
|
+
}
|
246
|
+
},
|
247
|
+
included: [
|
248
|
+
{
|
249
|
+
type: 'genre',
|
250
|
+
id: 1,
|
251
|
+
attributes: {
|
252
|
+
name: 'Genre one'
|
253
|
+
}
|
254
|
+
}
|
255
|
+
]
|
256
|
+
}
|
257
|
+
```
|
258
|
+
|
259
|
+
Will translate to:
|
260
|
+
```
|
261
|
+
{
|
262
|
+
movie: {
|
263
|
+
title: 'The Terminator',
|
264
|
+
genres_attributes: [{ id: 1, name: 'Genre one' }]
|
265
|
+
}
|
266
|
+
}
|
267
|
+
```
|
268
|
+
|
269
|
+
|
63
270
|
#### Casing
|
64
271
|
|
65
272
|
If the input is in a different convention than `:snake`, you should specify that.
|
data/Rakefile
CHANGED
@@ -15,13 +15,6 @@ RDoc::Task.new(:rdoc) do |rdoc|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
require 'bundler/gem_tasks'
|
18
|
+
require 'rspec/core/rake_task'
|
18
19
|
|
19
|
-
|
20
|
-
|
21
|
-
Rake::TestTask.new(:test) do |t|
|
22
|
-
t.libs << 'test'
|
23
|
-
t.pattern = 'test/**/*_test.rb'
|
24
|
-
t.verbose = false
|
25
|
-
end
|
26
|
-
|
27
|
-
task default: :test
|
20
|
+
task :default => :spec
|
data/lib/jsonapi_parameters.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'jsonapi_parameters/core_ext/action_controller/parameters'
|
2
|
+
require 'jsonapi_parameters/core_ext/action_dispatch/http/mime_type'
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module JsonApi::Parameters
|
2
|
+
include ActiveSupport::Inflector
|
3
|
+
|
2
4
|
def jsonapify(params, naming_convention: :snake)
|
3
5
|
jsonapi_translate(params, naming_convention: naming_convention)
|
4
6
|
end
|
@@ -60,9 +62,9 @@ module JsonApi::Parameters
|
|
60
62
|
end
|
61
63
|
|
62
64
|
def handle_to_many_relation(relationship_key, relationship_value)
|
63
|
-
|
65
|
+
with_inclusion = true
|
64
66
|
|
65
|
-
|
67
|
+
vals = relationship_value.map do |relationship_value|
|
66
68
|
related_id = relationship_value.dig(:id)
|
67
69
|
related_type = relationship_value.dig(:type)
|
68
70
|
|
@@ -70,26 +72,46 @@ module JsonApi::Parameters
|
|
70
72
|
related_id: related_id, related_type: related_type
|
71
73
|
) || {}
|
72
74
|
|
73
|
-
|
75
|
+
# If at least one related object has not been found in `included` tree,
|
76
|
+
# we should not attempt to "#{relationship_key}_attributes" but
|
77
|
+
# "#{relationship_key}_ids" instead.
|
78
|
+
with_inclusion = with_inclusion ? !included_object.empty? : with_inclusion
|
79
|
+
|
80
|
+
if with_inclusion
|
81
|
+
included_object.delete(:type)
|
82
|
+
included_object[:attributes].merge(id: related_id)
|
83
|
+
else
|
84
|
+
relationship_value.dig(:id)
|
85
|
+
end
|
86
|
+
end
|
74
87
|
|
75
|
-
|
88
|
+
# We may have smells in our value array as `with_inclusion` may have been changed at some point
|
89
|
+
# but not in the beginning.
|
90
|
+
# Because of that we should clear it and make sure the results are unified (e.g. array of ids)
|
91
|
+
unless with_inclusion
|
92
|
+
vals.map do |val|
|
93
|
+
val.dig(:attributes, :id) if val.is_a?(Hash)
|
94
|
+
end
|
76
95
|
end
|
77
96
|
|
78
|
-
|
97
|
+
key = with_inclusion ? "#{pluralize(relationship_key)}_attributes".to_sym : "#{singularize(relationship_key)}_ids".to_sym
|
98
|
+
|
99
|
+
[key, vals]
|
79
100
|
end
|
80
101
|
|
81
102
|
def handle_to_one_relation(relationship_key, relationship_value)
|
82
103
|
related_id = relationship_value.dig(:id)
|
83
|
-
related_type =
|
104
|
+
related_type = relationship_value.dig(:type)
|
84
105
|
|
85
106
|
included_object = find_included_object(
|
86
107
|
related_id: related_id, related_type: related_type
|
87
|
-
)
|
108
|
+
) || {}
|
88
109
|
|
89
|
-
return ["#{
|
110
|
+
return ["#{singularize(relationship_key)}_id".to_sym, related_id] if included_object.empty?
|
90
111
|
|
91
112
|
included_object.delete(:type)
|
92
|
-
[
|
113
|
+
included_object = included_object[:attributes].merge(id: related_id)
|
114
|
+
["#{singularize(relationship_key)}_attributes".to_sym, included_object]
|
93
115
|
end
|
94
116
|
|
95
117
|
def find_included_object(related_id:, related_type:)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi_parameters
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Visuality
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-
|
12
|
+
date: 2019-05-22 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -235,6 +235,34 @@ dependencies:
|
|
235
235
|
- - "~>"
|
236
236
|
- !ruby/object:Gem::Version
|
237
237
|
version: 0.3.8
|
238
|
+
- !ruby/object:Gem::Dependency
|
239
|
+
name: simplecov
|
240
|
+
requirement: !ruby/object:Gem::Requirement
|
241
|
+
requirements:
|
242
|
+
- - "~>"
|
243
|
+
- !ruby/object:Gem::Version
|
244
|
+
version: 0.16.1
|
245
|
+
type: :development
|
246
|
+
prerelease: false
|
247
|
+
version_requirements: !ruby/object:Gem::Requirement
|
248
|
+
requirements:
|
249
|
+
- - "~>"
|
250
|
+
- !ruby/object:Gem::Version
|
251
|
+
version: 0.16.1
|
252
|
+
- !ruby/object:Gem::Dependency
|
253
|
+
name: simplecov-console
|
254
|
+
requirement: !ruby/object:Gem::Requirement
|
255
|
+
requirements:
|
256
|
+
- - "~>"
|
257
|
+
- !ruby/object:Gem::Version
|
258
|
+
version: 0.4.2
|
259
|
+
type: :development
|
260
|
+
prerelease: false
|
261
|
+
version_requirements: !ruby/object:Gem::Requirement
|
262
|
+
requirements:
|
263
|
+
- - "~>"
|
264
|
+
- !ruby/object:Gem::Version
|
265
|
+
version: 0.4.2
|
238
266
|
description: JsonApi::Parameters allows you to easily translate JSON:API compliant
|
239
267
|
parameters to a structure expected by Rails.
|
240
268
|
email:
|