jsonapi-resources 0.1.1 → 0.2.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 +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
|