jsonapi-resources 0.1.1 → 0.2.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 +68 -1
- data/Rakefile +3 -7
- data/lib/jsonapi-resources.rb +1 -0
- data/lib/jsonapi/configuration.rb +29 -4
- data/lib/jsonapi/error_codes.rb +6 -2
- data/lib/jsonapi/exceptions.rb +92 -19
- data/lib/jsonapi/operation.rb +0 -18
- data/lib/jsonapi/paginator.rb +98 -0
- data/lib/jsonapi/request.rb +257 -182
- data/lib/jsonapi/resource.rb +58 -47
- data/lib/jsonapi/resource_controller.rb +85 -29
- data/lib/jsonapi/resource_serializer.rb +88 -33
- data/lib/jsonapi/resources/version.rb +1 -1
- data/lib/jsonapi/routing_ext.rb +38 -12
- data/test/controllers/controller_test.rb +761 -455
- data/test/fixtures/active_record.rb +90 -18
- data/test/integration/requests/request_test.rb +183 -25
- data/test/integration/routes/routes_test.rb +0 -5
- data/test/test_helper.rb +31 -7
- data/test/unit/operation/operations_processor_test.rb +28 -1
- data/test/unit/resource/resource_test.rb +4 -0
- data/test/unit/serializer/serializer_test.rb +882 -377
- metadata +3 -2
@@ -105,6 +105,18 @@ ActiveRecord::Schema.define do
|
|
105
105
|
t.binary :photo, limit: 1.kilobyte
|
106
106
|
t.boolean :cool
|
107
107
|
end
|
108
|
+
|
109
|
+
create_table :books, force: true do |t|
|
110
|
+
t.string :title
|
111
|
+
t.string :isbn
|
112
|
+
end
|
113
|
+
|
114
|
+
create_table :book_comments, force: true do |t|
|
115
|
+
t.text :body
|
116
|
+
t.belongs_to :book, index: true
|
117
|
+
t.integer :author_id
|
118
|
+
t.timestamps
|
119
|
+
end
|
108
120
|
end
|
109
121
|
|
110
122
|
### MODELS
|
@@ -202,6 +214,15 @@ class Breed
|
|
202
214
|
end
|
203
215
|
end
|
204
216
|
|
217
|
+
class Book < ActiveRecord::Base
|
218
|
+
has_many :book_comments
|
219
|
+
end
|
220
|
+
|
221
|
+
class BookComment < ActiveRecord::Base
|
222
|
+
belongs_to :author, class_name: 'Person', foreign_key: 'author_id'
|
223
|
+
belongs_to :book
|
224
|
+
end
|
225
|
+
|
205
226
|
class BreedData
|
206
227
|
def initialize
|
207
228
|
@breeds = {}
|
@@ -234,16 +255,20 @@ $breed_data.add(Breed.new(3, 'to_delete'))
|
|
234
255
|
|
235
256
|
### CONTROLLERS
|
236
257
|
class AuthorsController < JSONAPI::ResourceController
|
237
|
-
|
238
258
|
end
|
239
259
|
|
240
260
|
class PeopleController < JSONAPI::ResourceController
|
241
|
-
|
242
261
|
end
|
243
262
|
|
244
263
|
class PostsController < JSONAPI::ResourceController
|
245
264
|
end
|
246
265
|
|
266
|
+
class CommentsController < JSONAPI::ResourceController
|
267
|
+
end
|
268
|
+
|
269
|
+
class SectionsController < JSONAPI::ResourceController
|
270
|
+
end
|
271
|
+
|
247
272
|
class TagsController < JSONAPI::ResourceController
|
248
273
|
end
|
249
274
|
|
@@ -308,6 +333,12 @@ module Api
|
|
308
333
|
|
309
334
|
class PreferencesController < JSONAPI::ResourceController
|
310
335
|
end
|
336
|
+
|
337
|
+
class BooksController < JSONAPI::ResourceController
|
338
|
+
end
|
339
|
+
|
340
|
+
class BookCommentsController < JSONAPI::ResourceController
|
341
|
+
end
|
311
342
|
end
|
312
343
|
|
313
344
|
module V3
|
@@ -324,6 +355,9 @@ module Api
|
|
324
355
|
|
325
356
|
class IsoCurrenciesController < JSONAPI::ResourceController
|
326
357
|
end
|
358
|
+
|
359
|
+
class BooksController < JSONAPI::ResourceController
|
360
|
+
end
|
327
361
|
end
|
328
362
|
|
329
363
|
module V5
|
@@ -362,7 +396,7 @@ class PersonResource < JSONAPI::Resource
|
|
362
396
|
end
|
363
397
|
|
364
398
|
class AuthorResource < JSONAPI::Resource
|
365
|
-
attributes :
|
399
|
+
attributes :name, :email
|
366
400
|
model_name 'Person'
|
367
401
|
has_many :posts
|
368
402
|
|
@@ -385,14 +419,14 @@ class AuthorResource < JSONAPI::Resource
|
|
385
419
|
end
|
386
420
|
|
387
421
|
class CommentResource < JSONAPI::Resource
|
388
|
-
attributes :
|
422
|
+
attributes :body
|
389
423
|
has_one :post
|
390
424
|
has_one :author, class_name: 'Person'
|
391
425
|
has_many :tags
|
392
426
|
end
|
393
427
|
|
394
428
|
class TagResource < JSONAPI::Resource
|
395
|
-
attributes :
|
429
|
+
attributes :name
|
396
430
|
|
397
431
|
has_many :posts
|
398
432
|
# Not including the planets association so they don't get output
|
@@ -404,7 +438,6 @@ class SectionResource < JSONAPI::Resource
|
|
404
438
|
end
|
405
439
|
|
406
440
|
class PostResource < JSONAPI::Resource
|
407
|
-
attribute :id
|
408
441
|
attribute :title
|
409
442
|
attribute :body
|
410
443
|
attribute :subject
|
@@ -451,7 +484,7 @@ class PostResource < JSONAPI::Resource
|
|
451
484
|
end
|
452
485
|
|
453
486
|
filters :title, :author, :tags, :comments
|
454
|
-
|
487
|
+
filters :id, :ids
|
455
488
|
|
456
489
|
def self.updateable_fields(context)
|
457
490
|
super(context) - [:author, :subject]
|
@@ -469,6 +502,9 @@ class PostResource < JSONAPI::Resource
|
|
469
502
|
case filter
|
470
503
|
when :id
|
471
504
|
verify_keys(values, context)
|
505
|
+
when :ids #coerce :ids to :id
|
506
|
+
verify_keys(values, context)
|
507
|
+
return :id, values
|
472
508
|
end
|
473
509
|
return filter, values
|
474
510
|
end
|
@@ -490,19 +526,27 @@ end
|
|
490
526
|
|
491
527
|
class IsoCurrencyResource < JSONAPI::Resource
|
492
528
|
primary_key :code
|
493
|
-
attributes :
|
529
|
+
attributes :name, :country_name, :minor_unit
|
494
530
|
|
495
531
|
filter :country_name
|
496
532
|
end
|
497
533
|
|
498
534
|
class ExpenseEntryResource < JSONAPI::Resource
|
499
|
-
attributes :
|
535
|
+
attributes :cost
|
500
536
|
attribute :transaction_date, format: :date
|
501
537
|
|
502
538
|
has_one :iso_currency, foreign_key: 'currency_code'
|
503
539
|
has_one :employee, class_name: 'Person'
|
504
540
|
end
|
505
541
|
|
542
|
+
class EmployeeResource < JSONAPI::Resource
|
543
|
+
attributes :name, :email
|
544
|
+
model_name 'Person'
|
545
|
+
end
|
546
|
+
|
547
|
+
class FriendResource < JSONAPI::Resource
|
548
|
+
end
|
549
|
+
|
506
550
|
class BreedResource < JSONAPI::Resource
|
507
551
|
attribute :id, format_misspelled: :does_not_exist
|
508
552
|
attribute :name, format: :title
|
@@ -528,7 +572,6 @@ class BreedResource < JSONAPI::Resource
|
|
528
572
|
end
|
529
573
|
|
530
574
|
class PlanetResource < JSONAPI::Resource
|
531
|
-
attribute :id
|
532
575
|
attribute :name
|
533
576
|
attribute :description
|
534
577
|
|
@@ -539,18 +582,17 @@ class PlanetResource < JSONAPI::Resource
|
|
539
582
|
end
|
540
583
|
|
541
584
|
class PropertyResource < JSONAPI::Resource
|
542
|
-
attributes :
|
585
|
+
attributes :name
|
543
586
|
|
544
587
|
has_many :planets
|
545
588
|
end
|
546
589
|
|
547
590
|
class PlanetTypeResource < JSONAPI::Resource
|
548
|
-
attributes :
|
591
|
+
attributes :name
|
549
592
|
has_many :planets
|
550
593
|
end
|
551
594
|
|
552
595
|
class MoonResource < JSONAPI::Resource
|
553
|
-
attribute :id
|
554
596
|
attribute :name
|
555
597
|
attribute :description
|
556
598
|
|
@@ -558,11 +600,10 @@ class MoonResource < JSONAPI::Resource
|
|
558
600
|
end
|
559
601
|
|
560
602
|
class PreferencesResource < JSONAPI::Resource
|
561
|
-
attribute :id
|
562
603
|
attribute :advanced_mode
|
563
604
|
|
564
605
|
has_one :author, foreign_key: :person_id
|
565
|
-
has_many :friends
|
606
|
+
has_many :friends, class_name: 'Person'
|
566
607
|
|
567
608
|
def self.find_by_key(key, options = {})
|
568
609
|
new(Preferences.first)
|
@@ -570,7 +611,6 @@ class PreferencesResource < JSONAPI::Resource
|
|
570
611
|
end
|
571
612
|
|
572
613
|
class FactResource < JSONAPI::Resource
|
573
|
-
attribute :id
|
574
614
|
attribute :spouse_name
|
575
615
|
attribute :bio
|
576
616
|
attribute :quality_rating
|
@@ -585,7 +625,7 @@ end
|
|
585
625
|
module Api
|
586
626
|
module V1
|
587
627
|
class WriterResource < JSONAPI::Resource
|
588
|
-
attributes :
|
628
|
+
attributes :name, :email
|
589
629
|
model_name 'Person'
|
590
630
|
has_many :posts
|
591
631
|
|
@@ -597,7 +637,6 @@ module Api
|
|
597
637
|
|
598
638
|
class PostResource < JSONAPI::Resource
|
599
639
|
# V1 no longer supports tags and now calls author 'writer'
|
600
|
-
attribute :id
|
601
640
|
attribute :title
|
602
641
|
attribute :body
|
603
642
|
attribute :subject
|
@@ -625,6 +664,8 @@ module Api
|
|
625
664
|
PlanetTypeResource = PlanetTypeResource.dup
|
626
665
|
MoonResource = MoonResource.dup
|
627
666
|
PreferencesResource = PreferencesResource.dup
|
667
|
+
EmployeeResource = EmployeeResource.dup
|
668
|
+
FriendResource = FriendResource.dup
|
628
669
|
end
|
629
670
|
end
|
630
671
|
|
@@ -632,7 +673,21 @@ module Api
|
|
632
673
|
module V2
|
633
674
|
PreferencesResource = PreferencesResource.dup
|
634
675
|
AuthorResource = AuthorResource.dup
|
676
|
+
PersonResource = PersonResource.dup
|
635
677
|
PostResource = PostResource.dup
|
678
|
+
|
679
|
+
class BookResource < JSONAPI::Resource
|
680
|
+
attribute :title
|
681
|
+
attribute :isbn
|
682
|
+
|
683
|
+
has_many :book_comments
|
684
|
+
end
|
685
|
+
|
686
|
+
class BookCommentResource < JSONAPI::Resource
|
687
|
+
attributes :body
|
688
|
+
has_one :book
|
689
|
+
has_one :author, class_name: 'Person'
|
690
|
+
end
|
636
691
|
end
|
637
692
|
end
|
638
693
|
|
@@ -648,14 +703,20 @@ module Api
|
|
648
703
|
PostResource = PostResource.dup
|
649
704
|
ExpenseEntryResource = ExpenseEntryResource.dup
|
650
705
|
IsoCurrencyResource = IsoCurrencyResource.dup
|
706
|
+
|
707
|
+
class BookResource < Api::V2::BookResource
|
708
|
+
paginator :paged
|
709
|
+
end
|
651
710
|
end
|
652
711
|
end
|
653
712
|
|
654
713
|
module Api
|
655
714
|
module V5
|
715
|
+
AuthorResource = AuthorResource.dup
|
656
716
|
PostResource = PostResource.dup
|
657
717
|
ExpenseEntryResource = ExpenseEntryResource.dup
|
658
718
|
IsoCurrencyResource = IsoCurrencyResource.dup
|
719
|
+
EmployeeResource = EmployeeResource.dup
|
659
720
|
end
|
660
721
|
end
|
661
722
|
|
@@ -841,3 +902,14 @@ fact = Fact.create(spouse_name: 'Jane Author',
|
|
841
902
|
photo: "abc",
|
842
903
|
cool: false
|
843
904
|
)
|
905
|
+
|
906
|
+
for book_num in 0..999
|
907
|
+
Book.create(title: "Book #{book_num}", isbn: "12345-#{book_num}-67890") do |book|
|
908
|
+
book.save
|
909
|
+
if book_num < 5
|
910
|
+
for comment_num in 0..50
|
911
|
+
book.book_comments.create(body: "This is comment #{comment_num} on book #{book_num}.", author_id: a.id, book_id: book.id)
|
912
|
+
end
|
913
|
+
end
|
914
|
+
end
|
915
|
+
end
|
@@ -3,56 +3,87 @@ require File.expand_path('../../../fixtures/active_record', __FILE__)
|
|
3
3
|
|
4
4
|
class RequestTest < ActionDispatch::IntegrationTest
|
5
5
|
|
6
|
+
def setup
|
7
|
+
JSONAPI.configuration.json_key_format = :underscored_key
|
8
|
+
end
|
9
|
+
|
10
|
+
def after_teardown
|
11
|
+
Api::V2::BookResource.paginator :offset
|
12
|
+
JSONAPI.configuration.route_format = :underscored_route
|
13
|
+
end
|
14
|
+
|
6
15
|
def test_get
|
7
16
|
get '/posts'
|
8
17
|
assert_equal 200, status
|
9
18
|
end
|
10
19
|
|
20
|
+
def test_get_nested_has_one
|
21
|
+
get '/posts/1/author'
|
22
|
+
assert_equal 200, status
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_get_nested_has_many
|
26
|
+
get '/posts/1/comments'
|
27
|
+
assert_equal 200, status
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_get_nested_has_many_bad_param
|
31
|
+
get '/posts/1/comments?association=books'
|
32
|
+
assert_equal 200, status
|
33
|
+
end
|
34
|
+
|
11
35
|
def test_get_underscored_key
|
12
36
|
JSONAPI.configuration.json_key_format = :underscored_key
|
13
37
|
get '/iso_currencies'
|
14
38
|
assert_equal 200, status
|
15
|
-
assert_equal 3, json_response['
|
39
|
+
assert_equal 3, json_response['data'].size
|
16
40
|
end
|
17
41
|
|
18
42
|
def test_get_underscored_key_filtered
|
19
43
|
JSONAPI.configuration.json_key_format = :underscored_key
|
20
|
-
get '/iso_currencies?country_name=Canada'
|
44
|
+
get '/iso_currencies?filter[country_name]=Canada'
|
21
45
|
assert_equal 200, status
|
22
|
-
assert_equal 1, json_response['
|
23
|
-
assert_equal 'Canada', json_response['
|
46
|
+
assert_equal 1, json_response['data'].size
|
47
|
+
assert_equal 'Canada', json_response['data'][0]['country_name']
|
24
48
|
end
|
25
49
|
|
26
50
|
def test_get_camelized_key_filtered
|
27
51
|
JSONAPI.configuration.json_key_format = :camelized_key
|
28
|
-
get '/iso_currencies?countryName=Canada'
|
52
|
+
get '/iso_currencies?filter[countryName]=Canada'
|
29
53
|
assert_equal 200, status
|
30
|
-
assert_equal 1, json_response['
|
31
|
-
assert_equal 'Canada', json_response['
|
54
|
+
assert_equal 1, json_response['data'].size
|
55
|
+
assert_equal 'Canada', json_response['data'][0]['countryName']
|
32
56
|
end
|
33
57
|
|
34
58
|
def test_get_camelized_route_and_key_filtered
|
35
|
-
|
59
|
+
JSONAPI.configuration.json_key_format = :camelized_key
|
60
|
+
get '/api/v4/isoCurrencies?filter[countryName]=Canada'
|
36
61
|
assert_equal 200, status
|
37
|
-
assert_equal 1, json_response['
|
38
|
-
assert_equal 'Canada', json_response['
|
62
|
+
assert_equal 1, json_response['data'].size
|
63
|
+
assert_equal 'Canada', json_response['data'][0]['countryName']
|
39
64
|
end
|
40
65
|
|
41
66
|
def test_get_camelized_route_and_links
|
42
67
|
JSONAPI.configuration.json_key_format = :camelized_key
|
68
|
+
JSONAPI.configuration.route_format = :camelized_route
|
43
69
|
get '/api/v4/expenseEntries/1/links/isoCurrency'
|
44
70
|
assert_equal 200, status
|
45
|
-
|
71
|
+
assert_hash_equals({'data' => {
|
72
|
+
'type' => 'isoCurrencies',
|
73
|
+
'id' => 'USD',
|
74
|
+
'self' => 'http://www.example.com/api/v4/expenseEntries/1/links/isoCurrency',
|
75
|
+
'resource' => 'http://www.example.com/api/v4/expenseEntries/1/isoCurrency'}}, json_response)
|
46
76
|
end
|
47
77
|
|
48
78
|
def test_put_single_without_content_type
|
49
79
|
put '/posts/3',
|
50
80
|
{
|
51
|
-
'
|
81
|
+
'data' => {
|
82
|
+
'type' => 'posts',
|
52
83
|
'id' => '3',
|
53
84
|
'title' => 'A great new Post',
|
54
85
|
'links' => {
|
55
|
-
'tags' => [3, 4]
|
86
|
+
'tags' => {type: 'tags', ids: [3, 4]}
|
56
87
|
}
|
57
88
|
}
|
58
89
|
}.to_json, "CONTENT_TYPE" => "application/json"
|
@@ -63,11 +94,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
63
94
|
def test_put_single
|
64
95
|
put '/posts/3',
|
65
96
|
{
|
66
|
-
'
|
97
|
+
'data' => {
|
98
|
+
'type' => 'posts',
|
67
99
|
'id' => '3',
|
68
100
|
'title' => 'A great new Post',
|
69
101
|
'links' => {
|
70
|
-
'tags' => [3, 4]
|
102
|
+
'tags' => {type: 'tags', ids: [3, 4]}
|
71
103
|
}
|
72
104
|
}
|
73
105
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -92,11 +124,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
92
124
|
def test_post_single
|
93
125
|
post '/posts',
|
94
126
|
{
|
95
|
-
'
|
127
|
+
'data' => {
|
128
|
+
'type' => 'posts',
|
96
129
|
'title' => 'A great new Post',
|
97
130
|
'body' => 'JSONAPIResources is the greatest thing since unsliced bread.',
|
98
131
|
'links' => {
|
99
|
-
'author' => '3'
|
132
|
+
'author' => {type: 'people', id: '3'}
|
100
133
|
}
|
101
134
|
}
|
102
135
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -104,16 +137,16 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
104
137
|
assert_equal 201, status
|
105
138
|
end
|
106
139
|
|
107
|
-
def
|
140
|
+
def test_update_association_without_content_type
|
108
141
|
ruby = Section.find_by(name: 'ruby')
|
109
|
-
put '/posts/3/links/section', { 'sections' => ruby.id.to_s }.to_json
|
142
|
+
put '/posts/3/links/section', { 'sections' => {type: 'sections', id: ruby.id.to_s }}.to_json
|
110
143
|
|
111
144
|
assert_equal 415, status
|
112
145
|
end
|
113
146
|
|
114
|
-
def
|
147
|
+
def test_update_association_has_one
|
115
148
|
ruby = Section.find_by(name: 'ruby')
|
116
|
-
put '/posts/3/links/section', { '
|
149
|
+
put '/posts/3/links/section', { 'data' => {type: 'sections', id: ruby.id.to_s }}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
117
150
|
|
118
151
|
assert_equal 204, status
|
119
152
|
end
|
@@ -131,11 +164,12 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
131
164
|
def test_put_content_type
|
132
165
|
put '/posts/3',
|
133
166
|
{
|
134
|
-
'
|
167
|
+
'data' => {
|
168
|
+
'type' => 'posts',
|
135
169
|
'id' => '3',
|
136
170
|
'title' => 'A great new Post',
|
137
171
|
'links' => {
|
138
|
-
'tags' => [3, 4]
|
172
|
+
'tags' => {type: 'tags', ids: [3, 4]}
|
139
173
|
}
|
140
174
|
}
|
141
175
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -146,10 +180,11 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
146
180
|
def test_post_correct_content_type
|
147
181
|
post '/posts',
|
148
182
|
{
|
149
|
-
'
|
183
|
+
'data' => {
|
184
|
+
'type' => 'posts',
|
150
185
|
'title' => 'A great new Post',
|
151
186
|
'links' => {
|
152
|
-
'author' => '3'
|
187
|
+
'author' => {type: 'people', id: '3'}
|
153
188
|
}
|
154
189
|
}
|
155
190
|
}.to_json, "CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
@@ -167,4 +202,127 @@ class RequestTest < ActionDispatch::IntegrationTest
|
|
167
202
|
delete '/posts/8,9'
|
168
203
|
assert_equal 204, status
|
169
204
|
end
|
205
|
+
|
206
|
+
def test_pagination_none
|
207
|
+
Api::V2::BookResource.paginator :none
|
208
|
+
get '/api/v2/books'
|
209
|
+
assert_equal 200, status
|
210
|
+
assert_equal 1000, json_response['data'].size
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_pagination_offset_style
|
214
|
+
Api::V2::BookResource.paginator :offset
|
215
|
+
get '/api/v2/books'
|
216
|
+
assert_equal 200, status
|
217
|
+
assert_equal JSONAPI.configuration.default_page_size, json_response['data'].size
|
218
|
+
assert_equal 'Book 0', json_response['data'][0]['title']
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_pagination_offset_style_offset
|
222
|
+
Api::V2::BookResource.paginator :offset
|
223
|
+
get '/api/v2/books?page[offset]=50'
|
224
|
+
assert_equal 200, status
|
225
|
+
assert_equal JSONAPI.configuration.default_page_size, json_response['data'].size
|
226
|
+
assert_equal 'Book 50', json_response['data'][0]['title']
|
227
|
+
end
|
228
|
+
|
229
|
+
def test_pagination_offset_style_offset_limit
|
230
|
+
Api::V2::BookResource.paginator :offset
|
231
|
+
get '/api/v2/books?page[offset]=50&page[limit]=20'
|
232
|
+
assert_equal 200, status
|
233
|
+
assert_equal 20, json_response['data'].size
|
234
|
+
assert_equal 'Book 50', json_response['data'][0]['title']
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_pagination_offset_bad_param
|
238
|
+
Api::V2::BookResource.paginator :offset
|
239
|
+
get '/api/v2/books?page[irishsetter]=50&page[limit]=20'
|
240
|
+
assert_equal 400, status
|
241
|
+
end
|
242
|
+
|
243
|
+
def test_pagination_related_resources_link
|
244
|
+
Api::V2::BookResource.paginator :offset
|
245
|
+
get '/api/v2/books?page[limit]=2'
|
246
|
+
assert_equal 200, status
|
247
|
+
assert_equal 2, json_response['data'].size
|
248
|
+
assert_equal 'http://www.example.com/api/v2/books/1/book_comments',
|
249
|
+
json_response['data'][0]['links']['book_comments']['resource']
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_pagination_related_resources_data
|
253
|
+
Api::V2::BookResource.paginator :offset
|
254
|
+
Api::V2::BookCommentResource.paginator :offset
|
255
|
+
get '/api/v2/books/1/book_comments?page[limit]=10'
|
256
|
+
assert_equal 200, status
|
257
|
+
assert_equal 10, json_response['data'].size
|
258
|
+
assert_equal 'This is comment 9 on book 0.', json_response['data'][9]['body']
|
259
|
+
end
|
260
|
+
|
261
|
+
def test_pagination_related_resources_data_includes
|
262
|
+
Api::V2::BookResource.paginator :offset
|
263
|
+
Api::V2::BookCommentResource.paginator :offset
|
264
|
+
get '/api/v2/books/1/book_comments?page[limit]=10&include=author,book'
|
265
|
+
assert_equal 200, status
|
266
|
+
assert_equal 10, json_response['data'].size
|
267
|
+
assert_equal 'This is comment 9 on book 0.', json_response['data'][9]['body']
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_flow_self
|
271
|
+
get '/posts'
|
272
|
+
assert_equal 200, status
|
273
|
+
post_1 = json_response['data'][0]
|
274
|
+
|
275
|
+
get post_1['links']['self']
|
276
|
+
assert_equal 200, status
|
277
|
+
assert_hash_equals post_1, json_response['data']
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_flow_link_has_one_self_link
|
281
|
+
get '/posts'
|
282
|
+
assert_equal 200, status
|
283
|
+
post_1 = json_response['data'][0]
|
284
|
+
|
285
|
+
get post_1['links']['author']['self']
|
286
|
+
assert_equal 200, status
|
287
|
+
assert_hash_equals(json_response, {'data' => post_1['links']['author']})
|
288
|
+
end
|
289
|
+
|
290
|
+
def test_flow_link_has_many_self_link
|
291
|
+
get '/posts'
|
292
|
+
assert_equal 200, status
|
293
|
+
post_1 = json_response['data'][0]
|
294
|
+
|
295
|
+
get post_1['links']['tags']['self']
|
296
|
+
assert_equal 200, status
|
297
|
+
assert_hash_equals(json_response,
|
298
|
+
{'data' => {
|
299
|
+
'self' => 'http://www.example.com/posts/1/links/tags',
|
300
|
+
'resource' => 'http://www.example.com/posts/1/tags',
|
301
|
+
'type' => 'tags', 'ids'=>['1', '2', '3']
|
302
|
+
}
|
303
|
+
})
|
304
|
+
end
|
305
|
+
|
306
|
+
def test_flow_link_has_many_self_link_put
|
307
|
+
get '/posts'
|
308
|
+
assert_equal 200, status
|
309
|
+
post_1 = json_response['data'][0]
|
310
|
+
|
311
|
+
post post_1['links']['tags']['self'],
|
312
|
+
{'data' => {'type' => 'tags', 'ids' => ['5']}}.to_json,
|
313
|
+
"CONTENT_TYPE" => JSONAPI::MEDIA_TYPE
|
314
|
+
|
315
|
+
assert_equal 204, status
|
316
|
+
|
317
|
+
get post_1['links']['tags']['self']
|
318
|
+
assert_equal 200, status
|
319
|
+
assert_hash_equals(json_response,
|
320
|
+
{'data' => {
|
321
|
+
'self' => 'http://www.example.com/posts/1/links/tags',
|
322
|
+
'resource' => 'http://www.example.com/posts/1/tags',
|
323
|
+
'type' => 'tags', 'ids'=>['1', '2', '3', '5']
|
324
|
+
}
|
325
|
+
})
|
326
|
+
end
|
327
|
+
|
170
328
|
end
|