jsonapi-resources 0.3.3 → 0.4.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 +274 -102
- data/jsonapi-resources.gemspec +1 -0
- data/lib/jsonapi-resources.rb +15 -0
- data/lib/jsonapi/active_record_operations_processor.rb +21 -10
- data/lib/jsonapi/acts_as_resource_controller.rb +175 -0
- data/lib/jsonapi/configuration.rb +11 -0
- data/lib/jsonapi/error_codes.rb +7 -4
- data/lib/jsonapi/exceptions.rb +23 -15
- data/lib/jsonapi/formatter.rb +5 -5
- data/lib/jsonapi/include_directives.rb +67 -0
- data/lib/jsonapi/operation.rb +185 -65
- data/lib/jsonapi/operation_result.rb +38 -5
- data/lib/jsonapi/operation_results.rb +33 -0
- data/lib/jsonapi/operations_processor.rb +49 -9
- data/lib/jsonapi/paginator.rb +31 -17
- data/lib/jsonapi/request.rb +347 -163
- data/lib/jsonapi/resource.rb +159 -56
- data/lib/jsonapi/resource_controller.rb +1 -234
- data/lib/jsonapi/resource_serializer.rb +55 -69
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/response_document.rb +87 -0
- data/lib/jsonapi/routing_ext.rb +17 -11
- data/test/controllers/controller_test.rb +602 -326
- data/test/fixtures/active_record.rb +96 -6
- data/test/fixtures/line_items.yml +7 -1
- data/test/fixtures/numeros_telefone.yml +3 -0
- data/test/fixtures/purchase_orders.yml +6 -0
- data/test/integration/requests/request_test.rb +129 -60
- data/test/integration/routes/routes_test.rb +17 -17
- data/test/test_helper.rb +23 -5
- data/test/unit/jsonapi_request/jsonapi_request_test.rb +48 -0
- data/test/unit/operation/operations_processor_test.rb +242 -54
- data/test/unit/resource/resource_test.rb +108 -2
- data/test/unit/serializer/include_directives_test.rb +108 -0
- data/test/unit/serializer/response_document_test.rb +61 -0
- data/test/unit/serializer/serializer_test.rb +679 -520
- metadata +26 -2
@@ -3,6 +3,7 @@ require 'jsonapi-resources'
|
|
3
3
|
|
4
4
|
ActiveSupport::Inflector.inflections(:en) do |inflect|
|
5
5
|
inflect.uncountable 'preferences'
|
6
|
+
inflect.irregular 'numero_telefone', 'numeros_telefone'
|
6
7
|
end
|
7
8
|
|
8
9
|
### DATABASE
|
@@ -156,6 +157,16 @@ ActiveRecord::Schema.define do
|
|
156
157
|
create_table :hair_cuts, force: true do |t|
|
157
158
|
t.string :style
|
158
159
|
end
|
160
|
+
|
161
|
+
create_table :numeros_telefone, force: true do |t|
|
162
|
+
t.string :numero_telefone
|
163
|
+
t.timestamps null: false
|
164
|
+
end
|
165
|
+
|
166
|
+
create_table :categories, force: true do |t|
|
167
|
+
t.string :name
|
168
|
+
t.string :status, limit: 10
|
169
|
+
end
|
159
170
|
end
|
160
171
|
|
161
172
|
### MODELS
|
@@ -211,6 +222,16 @@ class Planet < ActiveRecord::Base
|
|
211
222
|
belongs_to :planet_type
|
212
223
|
|
213
224
|
has_and_belongs_to_many :tags, join_table: :planets_tags
|
225
|
+
|
226
|
+
# Test model callback cancelling save
|
227
|
+
before_save :check_not_pluto
|
228
|
+
|
229
|
+
def check_not_pluto
|
230
|
+
# Pluto can't be a planet, so cancel the save
|
231
|
+
if name.downcase == 'pluto'
|
232
|
+
return false
|
233
|
+
end
|
234
|
+
end
|
214
235
|
end
|
215
236
|
|
216
237
|
class PlanetType < ActiveRecord::Base
|
@@ -242,6 +263,7 @@ class Breed
|
|
242
263
|
@id = id
|
243
264
|
end
|
244
265
|
@name = name
|
266
|
+
@errors = ActiveModel::Errors.new(self)
|
245
267
|
end
|
246
268
|
|
247
269
|
attr_accessor :id, :name
|
@@ -250,7 +272,18 @@ class Breed
|
|
250
272
|
$breed_data.remove(@id)
|
251
273
|
end
|
252
274
|
|
253
|
-
def
|
275
|
+
def valid?
|
276
|
+
@errors.clear
|
277
|
+
if name.is_a?(String) && name.length > 0
|
278
|
+
return true
|
279
|
+
else
|
280
|
+
@errors.set(:name, ["can't be blank"])
|
281
|
+
return false
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def errors
|
286
|
+
@errors
|
254
287
|
end
|
255
288
|
end
|
256
289
|
|
@@ -304,6 +337,12 @@ class LineItem < ActiveRecord::Base
|
|
304
337
|
belongs_to :purchase_order
|
305
338
|
end
|
306
339
|
|
340
|
+
class NumeroTelefone < ActiveRecord::Base
|
341
|
+
end
|
342
|
+
|
343
|
+
class Category < ActiveRecord::Base
|
344
|
+
end
|
345
|
+
|
307
346
|
### PORO Data - don't do this in a production app
|
308
347
|
$breed_data = BreedData.new
|
309
348
|
$breed_data.add(Breed.new(0, 'persian'))
|
@@ -311,6 +350,19 @@ $breed_data.add(Breed.new(1, 'siamese'))
|
|
311
350
|
$breed_data.add(Breed.new(2, 'sphinx'))
|
312
351
|
$breed_data.add(Breed.new(3, 'to_delete'))
|
313
352
|
|
353
|
+
### OperationsProcessor
|
354
|
+
class CountingActiveRecordOperationsProcessor < ActiveRecordOperationsProcessor
|
355
|
+
after_find_operation do
|
356
|
+
|
357
|
+
count = @operation.resource_klass.find_count(@operation.resource_klass.verify_filters(@operation.filters, @context),
|
358
|
+
context: @context,
|
359
|
+
include_directives: @operation.include_directives,
|
360
|
+
sort_criteria: @operation.sort_criteria)
|
361
|
+
|
362
|
+
@operation_meta[:total_records] = count
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
314
366
|
### CONTROLLERS
|
315
367
|
class AuthorsController < JSONAPI::ResourceController
|
316
368
|
end
|
@@ -318,7 +370,8 @@ end
|
|
318
370
|
class PeopleController < JSONAPI::ResourceController
|
319
371
|
end
|
320
372
|
|
321
|
-
class PostsController <
|
373
|
+
class PostsController < ActionController::Base
|
374
|
+
include JSONAPI::ActsAsResourceController
|
322
375
|
end
|
323
376
|
|
324
377
|
class CommentsController < JSONAPI::ResourceController
|
@@ -342,6 +395,9 @@ end
|
|
342
395
|
class FactsController < JSONAPI::ResourceController
|
343
396
|
end
|
344
397
|
|
398
|
+
class CategoriesController < JSONAPI::ResourceController
|
399
|
+
end
|
400
|
+
|
345
401
|
### CONTROLLERS
|
346
402
|
module Api
|
347
403
|
module V1
|
@@ -351,7 +407,8 @@ module Api
|
|
351
407
|
class PeopleController < JSONAPI::ResourceController
|
352
408
|
end
|
353
409
|
|
354
|
-
class PostsController <
|
410
|
+
class PostsController < ActionController::Base
|
411
|
+
include JSONAPI::ActsAsResourceController
|
355
412
|
end
|
356
413
|
|
357
414
|
class TagsController < JSONAPI::ResourceController
|
@@ -459,6 +516,11 @@ module Api
|
|
459
516
|
class OrderFlagsController < JSONAPI::ResourceController
|
460
517
|
end
|
461
518
|
end
|
519
|
+
|
520
|
+
module V8
|
521
|
+
class NumerosTelefoneController < JSONAPI::ResourceController
|
522
|
+
end
|
523
|
+
end
|
462
524
|
end
|
463
525
|
|
464
526
|
### RESOURCES
|
@@ -492,6 +554,8 @@ class CommentResource < JSONAPI::Resource
|
|
492
554
|
has_one :post
|
493
555
|
has_one :author, class_name: 'Person'
|
494
556
|
has_many :tags
|
557
|
+
|
558
|
+
filters :body
|
495
559
|
end
|
496
560
|
|
497
561
|
class TagResource < JSONAPI::Resource
|
@@ -555,11 +619,11 @@ class PostResource < JSONAPI::Resource
|
|
555
619
|
filters :title, :author, :tags, :comments
|
556
620
|
filters :id, :ids
|
557
621
|
|
558
|
-
def self.
|
622
|
+
def self.updatable_fields(context)
|
559
623
|
super(context) - [:author, :subject]
|
560
624
|
end
|
561
625
|
|
562
|
-
def self.
|
626
|
+
def self.creatable_fields(context)
|
563
627
|
super(context) - [:subject]
|
564
628
|
end
|
565
629
|
|
@@ -643,6 +707,11 @@ class BreedResource < JSONAPI::Resource
|
|
643
707
|
def self.find_by_key(id, options = {})
|
644
708
|
BreedResource.new($breed_data.breeds[id.to_i], options[:context])
|
645
709
|
end
|
710
|
+
|
711
|
+
def _save
|
712
|
+
super
|
713
|
+
return :accepted
|
714
|
+
end
|
646
715
|
end
|
647
716
|
|
648
717
|
class PlanetResource < JSONAPI::Resource
|
@@ -696,6 +765,10 @@ class FactResource < JSONAPI::Resource
|
|
696
765
|
attribute :cool
|
697
766
|
end
|
698
767
|
|
768
|
+
class CategoryResource < JSONAPI::Resource
|
769
|
+
filter :status, default: 'active'
|
770
|
+
end
|
771
|
+
|
699
772
|
module Api
|
700
773
|
module V1
|
701
774
|
class WriterResource < JSONAPI::Resource
|
@@ -782,6 +855,10 @@ module Api
|
|
782
855
|
class BookResource < Api::V2::BookResource
|
783
856
|
paginator :paged
|
784
857
|
end
|
858
|
+
|
859
|
+
class BookCommentResource < Api::V2::BookCommentResource
|
860
|
+
paginator :paged
|
861
|
+
end
|
785
862
|
end
|
786
863
|
end
|
787
864
|
|
@@ -866,6 +943,12 @@ module Api
|
|
866
943
|
OrderFlagResource = V6::OrderFlagResource.dup
|
867
944
|
LineItemResource = V6::LineItemResource.dup
|
868
945
|
end
|
946
|
+
|
947
|
+
module V8
|
948
|
+
class NumeroTelefoneResource < JSONAPI::Resource
|
949
|
+
attribute :numero_telefone
|
950
|
+
end
|
951
|
+
end
|
869
952
|
end
|
870
953
|
|
871
954
|
warn 'start testing Name Collisions'
|
@@ -896,10 +979,17 @@ saturn = Planet.create(name: 'Satern',
|
|
896
979
|
description: 'Saturn is the sixth planet from the Sun and the second largest planet in the Solar System, after Jupiter.',
|
897
980
|
planet_type_id: planetoid.id)
|
898
981
|
titan = Moon.create(name:'Titan', description: 'Best known of the Saturn moons.', planet_id: saturn.id)
|
899
|
-
|
982
|
+
makemake = Planet.create(name: 'Makemake', description: 'A small planetoid in the Kuiperbelt.', planet_type_id: planetoid.id)
|
900
983
|
uranus = Planet.create(name: 'Uranus', description: 'Insert adolescent jokes here.', planet_type_id: gas_giant.id)
|
901
984
|
jupiter = Planet.create(name: 'Jupiter', description: 'A gas giant.', planet_type_id: gas_giant.id)
|
902
985
|
betax = Planet.create(name: 'Beta X', description: 'Newly discovered Planet X', planet_type_id: unknown.id)
|
903
986
|
betay = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Y', planet_type_id: unknown.id)
|
904
987
|
betaz = Planet.create(name: 'Beta X', description: 'Newly discovered Planet Z', planet_type_id: unknown.id)
|
905
988
|
betaw = Planet.create(name: 'Beta W', description: 'Newly discovered Planet W')
|
989
|
+
Category.create(name: 'Category A', status: 'active')
|
990
|
+
Category.create(name: 'Category B', status: 'active')
|
991
|
+
Category.create(name: 'Category C', status: 'active')
|
992
|
+
Category.create(name: 'Category D', status: 'inactive')
|
993
|
+
Category.create(name: 'Category E', status: 'inactive')
|
994
|
+
Category.create(name: 'Category F', status: 'inactive')
|
995
|
+
Category.create(name: 'Category G', status: 'inactive')
|
@@ -1,8 +1,6 @@
|
|
1
1
|
require File.expand_path('../../../test_helper', __FILE__)
|
2
|
-
require File.expand_path('../../../fixtures/active_record', __FILE__)
|
3
2
|
|
4
3
|
class RequestTest < ActionDispatch::IntegrationTest
|
5
|
-
|
6
4
|
def setup
|
7
5
|
JSONAPI.configuration.json_key_format = :underscored_key
|
8
6
|
JSONAPI.configuration.route_format = :underscored_route
|
@@ -18,6 +16,11 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
18
16
|
assert_equal 200, status
|
19
17
|
end
|
20
18
|
|
19
|
+
def test_get_inflected_resource
|
20
|
+
get '/api/v8/numeros_telefone'
|
21
|
+
assert_equal 200, status
|
22
|
+
end
|
23
|
+
|
21
24
|
def test_get_nested_has_one
|
22
25
|
get '/posts/1/author'
|
23
26
|
assert_equal 200, status
|
@@ -45,7 +48,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
45
48
|
get '/iso_currencies?filter[country_name]=Canada'
|
46
49
|
assert_equal 200, status
|
47
50
|
assert_equal 1, json_response['data'].size
|
48
|
-
assert_equal 'Canada', json_response['data'][0]['country_name']
|
51
|
+
assert_equal 'Canada', json_response['data'][0]['attributes']['country_name']
|
49
52
|
end
|
50
53
|
|
51
54
|
def test_get_camelized_key_filtered
|
@@ -53,7 +56,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
53
56
|
get '/iso_currencies?filter[countryName]=Canada'
|
54
57
|
assert_equal 200, status
|
55
58
|
assert_equal 1, json_response['data'].size
|
56
|
-
assert_equal 'Canada', json_response['data'][0]['countryName']
|
59
|
+
assert_equal 'Canada', json_response['data'][0]['attributes']['countryName']
|
57
60
|
end
|
58
61
|
|
59
62
|
def test_get_camelized_route_and_key_filtered
|
@@ -61,16 +64,16 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
61
64
|
get '/api/v4/isoCurrencies?filter[countryName]=Canada'
|
62
65
|
assert_equal 200, status
|
63
66
|
assert_equal 1, json_response['data'].size
|
64
|
-
assert_equal 'Canada', json_response['data'][0]['countryName']
|
67
|
+
assert_equal 'Canada', json_response['data'][0]['attributes']['countryName']
|
65
68
|
end
|
66
69
|
|
67
70
|
def test_get_camelized_route_and_links
|
68
71
|
JSONAPI.configuration.json_key_format = :camelized_key
|
69
72
|
JSONAPI.configuration.route_format = :camelized_route
|
70
|
-
get '/api/v4/expenseEntries/1/
|
73
|
+
get '/api/v4/expenseEntries/1/relationships/isoCurrency'
|
71
74
|
assert_equal 200, status
|
72
75
|
assert_hash_equals({'links' => {
|
73
|
-
'self' => 'http://www.example.com/api/v4/expenseEntries/1/
|
76
|
+
'self' => 'http://www.example.com/api/v4/expenseEntries/1/relationships/isoCurrency',
|
74
77
|
'related' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency'
|
75
78
|
},
|
76
79
|
'data' => {
|
@@ -88,7 +91,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
88
91
|
'type' => 'posts',
|
89
92
|
'id' => '3',
|
90
93
|
},
|
91
|
-
'
|
94
|
+
'attributes' => {
|
95
|
+
'title' => 'A great new Post'
|
96
|
+
},
|
92
97
|
'links' => {
|
93
98
|
'tags' => [
|
94
99
|
{type: 'tags', id: 3},
|
@@ -107,10 +112,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
107
112
|
'data' => {
|
108
113
|
'type' => 'posts',
|
109
114
|
'id' => '3',
|
110
|
-
'
|
111
|
-
|
115
|
+
'attributes' => {
|
116
|
+
'title' => 'A great new Post'
|
117
|
+
},
|
118
|
+
'relationships' => {
|
112
119
|
'tags' => {
|
113
|
-
'
|
120
|
+
'data' => [
|
114
121
|
{type: 'tags', id: 3},
|
115
122
|
{type: 'tags', id: 4}
|
116
123
|
]
|
@@ -126,10 +133,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
126
133
|
post '/posts',
|
127
134
|
{
|
128
135
|
'posts' => {
|
129
|
-
'
|
130
|
-
|
136
|
+
'attributes' => {
|
137
|
+
'title' => 'A great new Post'
|
138
|
+
},
|
139
|
+
'relationships' => {
|
131
140
|
'tags' => {
|
132
|
-
'
|
141
|
+
'data' => [
|
133
142
|
{type: 'tags', id: 3},
|
134
143
|
{type: 'tags', id: 4}
|
135
144
|
]
|
@@ -146,10 +155,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
146
155
|
{
|
147
156
|
'data' => {
|
148
157
|
'type' => 'posts',
|
149
|
-
'
|
150
|
-
|
151
|
-
|
152
|
-
|
158
|
+
'attributes' => {
|
159
|
+
'title' => 'A great new Post',
|
160
|
+
'body' => 'JSONAPIResources is the greatest thing since unsliced bread.'
|
161
|
+
},
|
162
|
+
'relationships' => {
|
163
|
+
'author' => {'data' => {type: 'people', id: '3'}}
|
153
164
|
}
|
154
165
|
}
|
155
166
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -176,9 +187,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
176
187
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
177
188
|
|
178
189
|
assert_equal 201, status
|
179
|
-
assert_nil json_response['data']['body']
|
180
|
-
assert_nil json_response['data']['
|
181
|
-
assert_nil json_response['data']['
|
190
|
+
assert_nil json_response['data']['attributes']['body']
|
191
|
+
assert_nil json_response['data']['relationships']['post']['data']
|
192
|
+
assert_nil json_response['data']['relationships']['author']['data']
|
182
193
|
end
|
183
194
|
|
184
195
|
def test_post_single_minimal_invalid
|
@@ -194,21 +205,21 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
194
205
|
|
195
206
|
def test_update_association_without_content_type
|
196
207
|
ruby = Section.find_by(name: 'ruby')
|
197
|
-
patch '/posts/3/
|
208
|
+
patch '/posts/3/relationships/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json
|
198
209
|
|
199
210
|
assert_equal 415, status
|
200
211
|
end
|
201
212
|
|
202
213
|
def test_patch_update_association_has_one
|
203
214
|
ruby = Section.find_by(name: 'ruby')
|
204
|
-
patch '/posts/3/
|
215
|
+
patch '/posts/3/relationships/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
205
216
|
|
206
217
|
assert_equal 204, status
|
207
218
|
end
|
208
219
|
|
209
220
|
def test_put_update_association_has_one
|
210
221
|
ruby = Section.find_by(name: 'ruby')
|
211
|
-
put '/posts/3/
|
222
|
+
put '/posts/3/relationships/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
212
223
|
|
213
224
|
assert_equal 204, status
|
214
225
|
end
|
@@ -217,14 +228,14 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
217
228
|
# Comments are acts_as_set=false so PUT/PATCH should respond with 403
|
218
229
|
|
219
230
|
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
220
|
-
patch '/posts/5/
|
231
|
+
patch '/posts/5/relationships/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
221
232
|
|
222
233
|
assert_equal 403, status
|
223
234
|
end
|
224
235
|
|
225
236
|
def test_post_update_association_has_many
|
226
237
|
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
227
|
-
post '/posts/5/
|
238
|
+
post '/posts/5/relationships/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
228
239
|
|
229
240
|
assert_equal 204, status
|
230
241
|
end
|
@@ -233,7 +244,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
233
244
|
# Comments are acts_as_set=false so PUT/PATCH should respond with 403. Note: JR currently treats PUT and PATCH as equivalent
|
234
245
|
|
235
246
|
rogue = Comment.find_by(body: 'Rogue Comment Here')
|
236
|
-
put '/posts/5/
|
247
|
+
put '/posts/5/relationships/comments', { 'data' => [{type: 'comments', id: rogue.id.to_s }]}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
237
248
|
|
238
249
|
assert_equal 403, status
|
239
250
|
end
|
@@ -254,10 +265,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
254
265
|
'data' => {
|
255
266
|
'type' => 'posts',
|
256
267
|
'id' => '3',
|
257
|
-
'
|
258
|
-
|
268
|
+
'attributes' => {
|
269
|
+
'title' => 'A great new Post'
|
270
|
+
},
|
271
|
+
'relationships' => {
|
259
272
|
'tags' => {
|
260
|
-
'
|
273
|
+
'data' => [
|
261
274
|
{type: 'tags', id: 3},
|
262
275
|
{type: 'tags', id: 4}
|
263
276
|
]
|
@@ -275,10 +288,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
275
288
|
'data' => {
|
276
289
|
'type' => 'posts',
|
277
290
|
'id' => '3',
|
278
|
-
'
|
279
|
-
|
291
|
+
'attributes' => {
|
292
|
+
'title' => 'A great new Post'
|
293
|
+
},
|
294
|
+
'relationships' => {
|
280
295
|
'tags' => {
|
281
|
-
'
|
296
|
+
'data' => [
|
282
297
|
{type: 'tags', id: 3},
|
283
298
|
{type: 'tags', id: 4}
|
284
299
|
]
|
@@ -295,9 +310,11 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
295
310
|
{
|
296
311
|
'data' => {
|
297
312
|
'type' => 'posts',
|
298
|
-
'
|
299
|
-
|
300
|
-
|
313
|
+
'attributes' => {
|
314
|
+
'title' => 'A great new Post'
|
315
|
+
},
|
316
|
+
'relationships' => {
|
317
|
+
'author' => {'data' => {type: 'people', id: '3'}}
|
301
318
|
}
|
302
319
|
}
|
303
320
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -328,7 +345,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
328
345
|
get '/api/v2/books'
|
329
346
|
assert_equal 200, status
|
330
347
|
assert_equal JSONAPI.configuration.default_page_size, json_response['data'].size
|
331
|
-
assert_equal 'Book 0', json_response['data'][0]['title']
|
348
|
+
assert_equal 'Book 0', json_response['data'][0]['attributes']['title']
|
332
349
|
end
|
333
350
|
|
334
351
|
def test_pagination_offset_style_offset
|
@@ -336,7 +353,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
336
353
|
get '/api/v2/books?page[offset]=50'
|
337
354
|
assert_equal 200, status
|
338
355
|
assert_equal JSONAPI.configuration.default_page_size, json_response['data'].size
|
339
|
-
assert_equal 'Book 50', json_response['data'][0]['title']
|
356
|
+
assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
|
340
357
|
end
|
341
358
|
|
342
359
|
def test_pagination_offset_style_offset_limit
|
@@ -344,7 +361,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
344
361
|
get '/api/v2/books?page[offset]=50&page[limit]=20'
|
345
362
|
assert_equal 200, status
|
346
363
|
assert_equal 20, json_response['data'].size
|
347
|
-
assert_equal 'Book 50', json_response['data'][0]['title']
|
364
|
+
assert_equal 'Book 50', json_response['data'][0]['attributes']['title']
|
348
365
|
end
|
349
366
|
|
350
367
|
def test_pagination_offset_bad_param
|
@@ -359,7 +376,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
359
376
|
assert_equal 200, status
|
360
377
|
assert_equal 2, json_response['data'].size
|
361
378
|
assert_equal 'http://www.example.com/api/v2/books/1/book_comments',
|
362
|
-
json_response['data'][1]['
|
379
|
+
json_response['data'][1]['relationships']['book_comments']['links']['related']
|
363
380
|
end
|
364
381
|
|
365
382
|
def test_pagination_related_resources_data
|
@@ -368,7 +385,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
368
385
|
get '/api/v2/books/1/book_comments?page[limit]=10'
|
369
386
|
assert_equal 200, status
|
370
387
|
assert_equal 10, json_response['data'].size
|
371
|
-
assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['body']
|
388
|
+
assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['attributes']['body']
|
372
389
|
end
|
373
390
|
|
374
391
|
def test_pagination_related_resources_data_includes
|
@@ -377,7 +394,7 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
377
394
|
get '/api/v2/books/1/book_comments?page[limit]=10&include=author,book'
|
378
395
|
assert_equal 200, status
|
379
396
|
assert_equal 10, json_response['data'].size
|
380
|
-
assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['body']
|
397
|
+
assert_equal 'This is comment 9 on book 1.', json_response['data'][9]['attributes']['body']
|
381
398
|
end
|
382
399
|
|
383
400
|
def test_flow_self
|
@@ -395,11 +412,11 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
395
412
|
assert_equal 200, status
|
396
413
|
post_1 = json_response['data'][0]
|
397
414
|
|
398
|
-
get post_1['
|
415
|
+
get post_1['relationships']['author']['links']['self']
|
399
416
|
assert_equal 200, status
|
400
417
|
assert_hash_equals(json_response, {
|
401
418
|
'links' => {
|
402
|
-
'self' => 'http://www.example.com/posts/1/
|
419
|
+
'self' => 'http://www.example.com/posts/1/relationships/author',
|
403
420
|
'related' => 'http://www.example.com/posts/1/author'
|
404
421
|
},
|
405
422
|
'data' => {type: 'people', id: '1'}
|
@@ -411,12 +428,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
411
428
|
assert_equal 200, status
|
412
429
|
post_1 = json_response['data'][0]
|
413
430
|
|
414
|
-
get post_1['
|
431
|
+
get post_1['relationships']['tags']['links']['self']
|
415
432
|
assert_equal 200, status
|
416
433
|
assert_hash_equals(json_response,
|
417
434
|
{
|
418
435
|
'links' => {
|
419
|
-
'self' => 'http://www.example.com/posts/1/
|
436
|
+
'self' => 'http://www.example.com/posts/1/relationships/tags',
|
420
437
|
'related' => 'http://www.example.com/posts/1/tags'
|
421
438
|
},
|
422
439
|
'data' => [
|
@@ -432,18 +449,18 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
432
449
|
assert_equal 200, status
|
433
450
|
post_1 = json_response['data'][4]
|
434
451
|
|
435
|
-
post post_1['
|
452
|
+
post post_1['relationships']['tags']['links']['self'],
|
436
453
|
{'data' => [{'type' => 'tags', 'id' => '10'}]}.to_json,
|
437
454
|
"CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
438
455
|
|
439
456
|
assert_equal 204, status
|
440
457
|
|
441
|
-
get post_1['
|
458
|
+
get post_1['relationships']['tags']['links']['self']
|
442
459
|
assert_equal 200, status
|
443
460
|
assert_hash_equals(json_response,
|
444
461
|
{
|
445
462
|
'links' => {
|
446
|
-
'self' => 'http://www.example.com/posts/5/
|
463
|
+
'self' => 'http://www.example.com/posts/5/relationships/tags',
|
447
464
|
'related' => 'http://www.example.com/posts/5/tags'
|
448
465
|
},
|
449
466
|
'data' => [
|
@@ -499,7 +516,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
499
516
|
post '/api/v6/purchase-orders',
|
500
517
|
{
|
501
518
|
'data' => {
|
502
|
-
'
|
519
|
+
'attributes' => {
|
520
|
+
'delivery-name' => 'ASDFG Corp'
|
521
|
+
},
|
503
522
|
'type' => 'purchase-orders'
|
504
523
|
}
|
505
524
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -513,7 +532,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
513
532
|
post '/api/v6/purchase-orders',
|
514
533
|
{
|
515
534
|
'data' => {
|
516
|
-
'
|
535
|
+
'attributes' => {
|
536
|
+
'delivery_name' => 'ASDFG Corp'
|
537
|
+
},
|
517
538
|
'type' => 'purchase_orders'
|
518
539
|
}
|
519
540
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -527,7 +548,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
527
548
|
post '/api/v7/purchase_orders',
|
528
549
|
{
|
529
550
|
'data' => {
|
530
|
-
'
|
551
|
+
'attributes' => {
|
552
|
+
'delivery-name' => 'ASDFG Corp'
|
553
|
+
},
|
531
554
|
'type' => 'purchase-orders'
|
532
555
|
}
|
533
556
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -541,7 +564,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
541
564
|
post '/api/v6/purchase-orders',
|
542
565
|
{
|
543
566
|
'data' => {
|
544
|
-
'
|
567
|
+
'attributes' => {
|
568
|
+
'delivery_name' => 'ASDFG Corp'
|
569
|
+
},
|
545
570
|
'type' => 'purchase-orders'
|
546
571
|
}
|
547
572
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -556,7 +581,9 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
556
581
|
{
|
557
582
|
'data' => {
|
558
583
|
'id' => '1',
|
559
|
-
'
|
584
|
+
'attributes' => {
|
585
|
+
'delivery-name' => 'ASDFG Corp'
|
586
|
+
},
|
560
587
|
'type' => 'purchase-orders'
|
561
588
|
}
|
562
589
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -572,10 +599,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
572
599
|
'data' => {
|
573
600
|
'id' => '1',
|
574
601
|
'type' => 'line-items',
|
575
|
-
'
|
576
|
-
|
602
|
+
'attributes' => {
|
603
|
+
'item-cost' => '23.57'
|
604
|
+
},
|
605
|
+
'relationships' => {
|
577
606
|
'purchase-order' => {
|
578
|
-
'
|
607
|
+
'data' => {'type' => 'purchase-orders', 'id' => '2'}
|
579
608
|
}
|
580
609
|
}
|
581
610
|
}
|
@@ -592,15 +621,15 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
592
621
|
'data' => {
|
593
622
|
'id' => '2',
|
594
623
|
'type' => 'purchase-orders',
|
595
|
-
'
|
624
|
+
'relationships' => {
|
596
625
|
'line-items' => {
|
597
|
-
'
|
626
|
+
'data' => [
|
598
627
|
{'type' => 'line-items', 'id' => '3'},
|
599
628
|
{'type' => 'line-items', 'id' => '4'}
|
600
629
|
]
|
601
630
|
},
|
602
631
|
'order-flags' => {
|
603
|
-
'
|
632
|
+
'data' => [
|
604
633
|
{'type' => 'order-flags', 'id' => '1'},
|
605
634
|
{'type' => 'order-flags', 'id' => '2'}
|
606
635
|
]
|
@@ -611,4 +640,44 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
611
640
|
|
612
641
|
assert_equal 200, status
|
613
642
|
end
|
643
|
+
|
644
|
+
def test_post_has_many_link
|
645
|
+
JSONAPI.configuration.route_format = :dasherized_route
|
646
|
+
JSONAPI.configuration.json_key_format = :dasherized_key
|
647
|
+
post '/api/v6/purchase-orders/3/relationships/line-items',
|
648
|
+
{
|
649
|
+
'data' => [
|
650
|
+
{'type' => 'line-items', 'id' => '3'},
|
651
|
+
{'type' => 'line-items', 'id' => '4'}
|
652
|
+
]
|
653
|
+
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
654
|
+
|
655
|
+
assert_equal 204, status
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_patch_has_many_link
|
659
|
+
JSONAPI.configuration.route_format = :dasherized_route
|
660
|
+
JSONAPI.configuration.json_key_format = :dasherized_key
|
661
|
+
patch '/api/v6/purchase-orders/3/relationships/order-flags',
|
662
|
+
{
|
663
|
+
'data' => [
|
664
|
+
{'type' => 'order-flags', 'id' => '1'},
|
665
|
+
{'type' => 'order-flags', 'id' => '2'}
|
666
|
+
]
|
667
|
+
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
668
|
+
|
669
|
+
assert_equal 204, status
|
670
|
+
end
|
671
|
+
|
672
|
+
def test_patch_has_one
|
673
|
+
JSONAPI.configuration.route_format = :dasherized_route
|
674
|
+
JSONAPI.configuration.json_key_format = :dasherized_key
|
675
|
+
patch '/api/v6/line-items/5/relationships/purchase-order',
|
676
|
+
{
|
677
|
+
'data' => {'type' => 'purchase-orders', 'id' => '3'}
|
678
|
+
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
679
|
+
|
680
|
+
assert_equal 204, status
|
681
|
+
end
|
682
|
+
|
614
683
|
end
|