media_types-serialization 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +137 -137
- data/README.md +93 -49
- data/lib/media_types/serialization.rb +39 -24
- data/lib/media_types/serialization/base.rb +4 -4
- data/lib/media_types/serialization/serialization_dsl.rb +3 -3
- data/lib/media_types/serialization/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2101630b0e9219ac970e8ce97c057f7f5281955219f6c3a4915979399190a0b5
|
4
|
+
data.tar.gz: 692a15e3dfaff3e9d8d306825dc9ab7d3cd8f5fa051b1918b0110215beaf7d5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77ea1c954ad749250eb9ee393fef00730de767cec2b8cd0c9a9c05e3edd38bf7ba9491260f7d4998751aee55fb005636cd3dcdb8aa2f146e7140fc5279519871
|
7
|
+
data.tar.gz: 1508f06953ce8611f7e6dd11983f0900a22ab7ee0a1e074250c58693210f6844822de7f34af564cd2b52c0dc383649e112f8737c6c411deca49764819ca28bca
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.3.0
|
4
|
+
|
5
|
+
- ✨ Add `formats:` to `output_html` and default it to `[:html]`, so rails behaves
|
6
|
+
- 🐛 Fix stale references to `render media:`
|
7
|
+
- 🐛 Fix inconsistent `context:` passing for `Serializer.serialize`
|
8
|
+
|
3
9
|
## 1.2.0
|
4
10
|
|
5
11
|
- ✨ Add `view:` to `output_html` which renders a specific rails view.
|
data/Gemfile.lock
CHANGED
@@ -1,137 +1,137 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
media_types-serialization (1.
|
5
|
-
actionpack (>= 4.0.0)
|
6
|
-
activesupport (>= 4.0.0)
|
7
|
-
media_types (>= 2.0.0, < 3.0.0)
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
actioncable (5.2.6)
|
13
|
-
actionpack (= 5.2.6)
|
14
|
-
nio4r (~> 2.0)
|
15
|
-
websocket-driver (>= 0.6.1)
|
16
|
-
actionmailer (5.2.6)
|
17
|
-
actionpack (= 5.2.6)
|
18
|
-
actionview (= 5.2.6)
|
19
|
-
activejob (= 5.2.6)
|
20
|
-
mail (~> 2.5, >= 2.5.4)
|
21
|
-
rails-dom-testing (~> 2.0)
|
22
|
-
actionpack (5.2.6)
|
23
|
-
actionview (= 5.2.6)
|
24
|
-
activesupport (= 5.2.6)
|
25
|
-
rack (~> 2.0, >= 2.0.8)
|
26
|
-
rack-test (>= 0.6.3)
|
27
|
-
rails-dom-testing (~> 2.0)
|
28
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
29
|
-
actionview (5.2.6)
|
30
|
-
activesupport (= 5.2.6)
|
31
|
-
builder (~> 3.1)
|
32
|
-
erubi (~> 1.4)
|
33
|
-
rails-dom-testing (~> 2.0)
|
34
|
-
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
35
|
-
activejob (5.2.6)
|
36
|
-
activesupport (= 5.2.6)
|
37
|
-
globalid (>= 0.3.6)
|
38
|
-
activemodel (5.2.6)
|
39
|
-
activesupport (= 5.2.6)
|
40
|
-
activerecord (5.2.6)
|
41
|
-
activemodel (= 5.2.6)
|
42
|
-
activesupport (= 5.2.6)
|
43
|
-
arel (>= 9.0)
|
44
|
-
activestorage (5.2.6)
|
45
|
-
actionpack (= 5.2.6)
|
46
|
-
activerecord (= 5.2.6)
|
47
|
-
marcel (~> 1.0.0)
|
48
|
-
activesupport (5.2.6)
|
49
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
50
|
-
i18n (>= 0.7, < 2)
|
51
|
-
minitest (~> 5.1)
|
52
|
-
tzinfo (~> 1.1)
|
53
|
-
arel (9.0.0)
|
54
|
-
awesome_print (1.9.2)
|
55
|
-
builder (3.2.4)
|
56
|
-
concurrent-ruby (1.1.9)
|
57
|
-
crass (1.0.6)
|
58
|
-
erubi (1.10.0)
|
59
|
-
globalid (0.4.2)
|
60
|
-
activesupport (>= 4.2.0)
|
61
|
-
i18n (1.8.10)
|
62
|
-
concurrent-ruby (~> 1.0)
|
63
|
-
loofah (2.10.0)
|
64
|
-
crass (~> 1.0.2)
|
65
|
-
nokogiri (>= 1.5.9)
|
66
|
-
mail (2.7.1)
|
67
|
-
mini_mime (>= 0.1.1)
|
68
|
-
marcel (1.0.1)
|
69
|
-
media_types (2.0.1)
|
70
|
-
method_source (1.0.0)
|
71
|
-
mini_mime (1.1.0)
|
72
|
-
minitest (5.14.4)
|
73
|
-
nio4r (2.5.7)
|
74
|
-
nokogiri (1.11.7-x64-mingw32)
|
75
|
-
racc (~> 1.4)
|
76
|
-
nokogiri (1.11.7-x86_64-linux)
|
77
|
-
racc (~> 1.4)
|
78
|
-
oj (3.12.
|
79
|
-
racc (1.5.2)
|
80
|
-
rack (2.2.3)
|
81
|
-
rack-test (1.1.0)
|
82
|
-
rack (>= 1.0, < 3)
|
83
|
-
rails (5.2.6)
|
84
|
-
actioncable (= 5.2.6)
|
85
|
-
actionmailer (= 5.2.6)
|
86
|
-
actionpack (= 5.2.6)
|
87
|
-
actionview (= 5.2.6)
|
88
|
-
activejob (= 5.2.6)
|
89
|
-
activemodel (= 5.2.6)
|
90
|
-
activerecord (= 5.2.6)
|
91
|
-
activestorage (= 5.2.6)
|
92
|
-
activesupport (= 5.2.6)
|
93
|
-
bundler (>= 1.3.0)
|
94
|
-
railties (= 5.2.6)
|
95
|
-
sprockets-rails (>= 2.0.0)
|
96
|
-
rails-dom-testing (2.0.3)
|
97
|
-
activesupport (>= 4.2.0)
|
98
|
-
nokogiri (>= 1.6)
|
99
|
-
rails-html-sanitizer (1.3.0)
|
100
|
-
loofah (~> 2.3)
|
101
|
-
railties (5.2.6)
|
102
|
-
actionpack (= 5.2.6)
|
103
|
-
activesupport (= 5.2.6)
|
104
|
-
method_source
|
105
|
-
rake (>= 0.8.7)
|
106
|
-
thor (>= 0.19.0, < 2.0)
|
107
|
-
rake (13.0.6)
|
108
|
-
sprockets (4.0.2)
|
109
|
-
concurrent-ruby (~> 1.0)
|
110
|
-
rack (> 1, < 3)
|
111
|
-
sprockets-rails (3.2.2)
|
112
|
-
actionpack (>= 4.0)
|
113
|
-
activesupport (>= 4.0)
|
114
|
-
sprockets (>= 3.0.0)
|
115
|
-
thor (1.1.0)
|
116
|
-
thread_safe (0.3.6)
|
117
|
-
tzinfo (1.2.9)
|
118
|
-
thread_safe (~> 0.1)
|
119
|
-
websocket-driver (0.7.5)
|
120
|
-
websocket-extensions (>= 0.1.0)
|
121
|
-
websocket-extensions (0.1.5)
|
122
|
-
|
123
|
-
PLATFORMS
|
124
|
-
x64-mingw32
|
125
|
-
x86_64-linux
|
126
|
-
|
127
|
-
DEPENDENCIES
|
128
|
-
awesome_print
|
129
|
-
bundler
|
130
|
-
media_types-serialization!
|
131
|
-
minitest (~> 5.0)
|
132
|
-
oj
|
133
|
-
rails (~> 5.2)
|
134
|
-
rake (~> 13.0)
|
135
|
-
|
136
|
-
BUNDLED WITH
|
137
|
-
2.2.7
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
media_types-serialization (1.3.0)
|
5
|
+
actionpack (>= 4.0.0)
|
6
|
+
activesupport (>= 4.0.0)
|
7
|
+
media_types (>= 2.0.0, < 3.0.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
actioncable (5.2.6)
|
13
|
+
actionpack (= 5.2.6)
|
14
|
+
nio4r (~> 2.0)
|
15
|
+
websocket-driver (>= 0.6.1)
|
16
|
+
actionmailer (5.2.6)
|
17
|
+
actionpack (= 5.2.6)
|
18
|
+
actionview (= 5.2.6)
|
19
|
+
activejob (= 5.2.6)
|
20
|
+
mail (~> 2.5, >= 2.5.4)
|
21
|
+
rails-dom-testing (~> 2.0)
|
22
|
+
actionpack (5.2.6)
|
23
|
+
actionview (= 5.2.6)
|
24
|
+
activesupport (= 5.2.6)
|
25
|
+
rack (~> 2.0, >= 2.0.8)
|
26
|
+
rack-test (>= 0.6.3)
|
27
|
+
rails-dom-testing (~> 2.0)
|
28
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
29
|
+
actionview (5.2.6)
|
30
|
+
activesupport (= 5.2.6)
|
31
|
+
builder (~> 3.1)
|
32
|
+
erubi (~> 1.4)
|
33
|
+
rails-dom-testing (~> 2.0)
|
34
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
35
|
+
activejob (5.2.6)
|
36
|
+
activesupport (= 5.2.6)
|
37
|
+
globalid (>= 0.3.6)
|
38
|
+
activemodel (5.2.6)
|
39
|
+
activesupport (= 5.2.6)
|
40
|
+
activerecord (5.2.6)
|
41
|
+
activemodel (= 5.2.6)
|
42
|
+
activesupport (= 5.2.6)
|
43
|
+
arel (>= 9.0)
|
44
|
+
activestorage (5.2.6)
|
45
|
+
actionpack (= 5.2.6)
|
46
|
+
activerecord (= 5.2.6)
|
47
|
+
marcel (~> 1.0.0)
|
48
|
+
activesupport (5.2.6)
|
49
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
50
|
+
i18n (>= 0.7, < 2)
|
51
|
+
minitest (~> 5.1)
|
52
|
+
tzinfo (~> 1.1)
|
53
|
+
arel (9.0.0)
|
54
|
+
awesome_print (1.9.2)
|
55
|
+
builder (3.2.4)
|
56
|
+
concurrent-ruby (1.1.9)
|
57
|
+
crass (1.0.6)
|
58
|
+
erubi (1.10.0)
|
59
|
+
globalid (0.4.2)
|
60
|
+
activesupport (>= 4.2.0)
|
61
|
+
i18n (1.8.10)
|
62
|
+
concurrent-ruby (~> 1.0)
|
63
|
+
loofah (2.10.0)
|
64
|
+
crass (~> 1.0.2)
|
65
|
+
nokogiri (>= 1.5.9)
|
66
|
+
mail (2.7.1)
|
67
|
+
mini_mime (>= 0.1.1)
|
68
|
+
marcel (1.0.1)
|
69
|
+
media_types (2.0.1)
|
70
|
+
method_source (1.0.0)
|
71
|
+
mini_mime (1.1.0)
|
72
|
+
minitest (5.14.4)
|
73
|
+
nio4r (2.5.7)
|
74
|
+
nokogiri (1.11.7-x64-mingw32)
|
75
|
+
racc (~> 1.4)
|
76
|
+
nokogiri (1.11.7-x86_64-linux)
|
77
|
+
racc (~> 1.4)
|
78
|
+
oj (3.12.3)
|
79
|
+
racc (1.5.2)
|
80
|
+
rack (2.2.3)
|
81
|
+
rack-test (1.1.0)
|
82
|
+
rack (>= 1.0, < 3)
|
83
|
+
rails (5.2.6)
|
84
|
+
actioncable (= 5.2.6)
|
85
|
+
actionmailer (= 5.2.6)
|
86
|
+
actionpack (= 5.2.6)
|
87
|
+
actionview (= 5.2.6)
|
88
|
+
activejob (= 5.2.6)
|
89
|
+
activemodel (= 5.2.6)
|
90
|
+
activerecord (= 5.2.6)
|
91
|
+
activestorage (= 5.2.6)
|
92
|
+
activesupport (= 5.2.6)
|
93
|
+
bundler (>= 1.3.0)
|
94
|
+
railties (= 5.2.6)
|
95
|
+
sprockets-rails (>= 2.0.0)
|
96
|
+
rails-dom-testing (2.0.3)
|
97
|
+
activesupport (>= 4.2.0)
|
98
|
+
nokogiri (>= 1.6)
|
99
|
+
rails-html-sanitizer (1.3.0)
|
100
|
+
loofah (~> 2.3)
|
101
|
+
railties (5.2.6)
|
102
|
+
actionpack (= 5.2.6)
|
103
|
+
activesupport (= 5.2.6)
|
104
|
+
method_source
|
105
|
+
rake (>= 0.8.7)
|
106
|
+
thor (>= 0.19.0, < 2.0)
|
107
|
+
rake (13.0.6)
|
108
|
+
sprockets (4.0.2)
|
109
|
+
concurrent-ruby (~> 1.0)
|
110
|
+
rack (> 1, < 3)
|
111
|
+
sprockets-rails (3.2.2)
|
112
|
+
actionpack (>= 4.0)
|
113
|
+
activesupport (>= 4.0)
|
114
|
+
sprockets (>= 3.0.0)
|
115
|
+
thor (1.1.0)
|
116
|
+
thread_safe (0.3.6)
|
117
|
+
tzinfo (1.2.9)
|
118
|
+
thread_safe (~> 0.1)
|
119
|
+
websocket-driver (0.7.5)
|
120
|
+
websocket-extensions (>= 0.1.0)
|
121
|
+
websocket-extensions (0.1.5)
|
122
|
+
|
123
|
+
PLATFORMS
|
124
|
+
x64-mingw32
|
125
|
+
x86_64-linux
|
126
|
+
|
127
|
+
DEPENDENCIES
|
128
|
+
awesome_print
|
129
|
+
bundler
|
130
|
+
media_types-serialization!
|
131
|
+
minitest (~> 5.0)
|
132
|
+
oj
|
133
|
+
rails (~> 5.2)
|
134
|
+
rake (~> 13.0)
|
135
|
+
|
136
|
+
BUNDLED WITH
|
137
|
+
2.2.7
|
data/README.md
CHANGED
@@ -79,11 +79,13 @@ class BookController < ActionController::API
|
|
79
79
|
end
|
80
80
|
```
|
81
81
|
|
82
|
-
While using the controller integration the context will always be set to the current controller.
|
82
|
+
While using the controller integration the context will always be set to the current controller.
|
83
|
+
This allows you to construct urls.
|
83
84
|
|
84
85
|
### Adding HATEOAS responses to existing routes
|
85
86
|
|
86
|
-
When creating a mobile application it's often useful to allow the app to request a non-html representation of a specific url.
|
87
|
+
When creating a mobile application it's often useful to allow the app to request a non-html representation of a specific url.
|
88
|
+
If you have an existing route:
|
87
89
|
|
88
90
|
```ruby
|
89
91
|
class BookController < ApplicationController
|
@@ -113,7 +115,9 @@ end
|
|
113
115
|
|
114
116
|
### Validations
|
115
117
|
|
116
|
-
Right now the serializer does not validate incoming or outgoing information.
|
118
|
+
Right now the serializer does not validate incoming or outgoing information.
|
119
|
+
This can cause issues when you accidentally emit non-conforming data that people start to depend on.
|
120
|
+
To make sure you don't do that you can specify a [Media Type validator](https://github.com/SleeplessByte/media-types-ruby):
|
117
121
|
|
118
122
|
```ruby
|
119
123
|
require 'media_types'
|
@@ -179,7 +183,8 @@ BookSerializer.serialize(book, BookValidator.version(2), context: nil)
|
|
179
183
|
|
180
184
|
### Links
|
181
185
|
|
182
|
-
When making [HATEOAS](https://docs.delftsolutions.nl/wiki/HATEOAS_API) compliant applications it's very useful to include `Link` headers in your response so clients can use a `HEAD` request instead of having to fetch the entire resource.
|
186
|
+
When making [HATEOAS](https://docs.delftsolutions.nl/wiki/HATEOAS_API) compliant applications it's very useful to include `Link` headers in your response so clients can use a `HEAD` request instead of having to fetch the entire resource.
|
187
|
+
Serializers have convenience methods to help with this:
|
183
188
|
|
184
189
|
```ruby
|
185
190
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -218,7 +223,8 @@ There are convenience methods for serializing arrays of objects based on a templ
|
|
218
223
|
|
219
224
|
#### Indexes
|
220
225
|
|
221
|
-
An index is a collection of urls that point to members of the array.
|
226
|
+
An index is a collection of urls that point to members of the array.
|
227
|
+
The index method automatically generates it based on the self links defined in the default view of the same version.
|
222
228
|
|
223
229
|
```ruby
|
224
230
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -260,7 +266,8 @@ BookSerializer.serialize([book], BookValidator.view(:index).version(3), context:
|
|
260
266
|
|
261
267
|
#### Collections
|
262
268
|
|
263
|
-
A collection inlines the member objects.
|
269
|
+
A collection inlines the member objects.
|
270
|
+
The collection method automatically generates it based on the default view of the same version.
|
264
271
|
|
265
272
|
```ruby
|
266
273
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -329,6 +336,7 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
329
336
|
attribute :title, obj.title
|
330
337
|
attribute :description, obj.description if version >= 2
|
331
338
|
end
|
339
|
+
end
|
332
340
|
|
333
341
|
input version: 3
|
334
342
|
end
|
@@ -344,7 +352,7 @@ class BookController < ActionController::API
|
|
344
352
|
book = Book.new
|
345
353
|
book.title = 'Everything, abridged'
|
346
354
|
|
347
|
-
|
355
|
+
render_media serialize_media(book)
|
348
356
|
end
|
349
357
|
|
350
358
|
def create
|
@@ -390,14 +398,14 @@ class BookController < ActionController::API
|
|
390
398
|
book = Book.new
|
391
399
|
book.title = 'Everything, abridged'
|
392
400
|
|
393
|
-
|
401
|
+
render_media serialize_media(book)
|
394
402
|
end
|
395
403
|
|
396
404
|
def create
|
397
405
|
book = deserialize(request)
|
398
406
|
book.save!
|
399
407
|
|
400
|
-
|
408
|
+
render_media serialize_media(book)
|
401
409
|
end
|
402
410
|
end
|
403
411
|
```
|
@@ -406,7 +414,9 @@ If you don't want to apply any input validation or deserialization you can use t
|
|
406
414
|
|
407
415
|
### Raw output
|
408
416
|
|
409
|
-
Sometimes you need to output raw data.
|
417
|
+
Sometimes you need to output raw data.
|
418
|
+
This cannot be validated.
|
419
|
+
You do this as follows:
|
410
420
|
|
411
421
|
```ruby
|
412
422
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -443,7 +453,8 @@ end
|
|
443
453
|
|
444
454
|
### Remapping media type identifiers
|
445
455
|
|
446
|
-
Sometimes you already have old clients using an `application/json` media type identifier when they do requests.
|
456
|
+
Sometimes you already have old clients using an `application/json` media type identifier when they do requests.
|
457
|
+
While this is not a good practise as this makes it hard to add new fields or remove old ones, this library has support for migrating away:
|
447
458
|
|
448
459
|
```ruby
|
449
460
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -475,7 +486,8 @@ Validation will be done using the remapped validator. Aliasses map to version `n
|
|
475
486
|
|
476
487
|
### HTML
|
477
488
|
|
478
|
-
This library has a built in API viewer.
|
489
|
+
This library has a built in API viewer.
|
490
|
+
The viewer can be accessed by by appending a `?api_viewer=last` query parameter to the URL.
|
479
491
|
|
480
492
|
To enable the API viewer, use: `allow_api_viewer` in the controller.
|
481
493
|
|
@@ -493,7 +505,7 @@ class BookController < ActionController::API
|
|
493
505
|
book = Book.new
|
494
506
|
book.title = 'Everything, abridged'
|
495
507
|
|
496
|
-
|
508
|
+
render_media serialize_media(book)
|
497
509
|
end
|
498
510
|
|
499
511
|
def create
|
@@ -531,17 +543,18 @@ end
|
|
531
543
|
|
532
544
|
#### Errors
|
533
545
|
|
534
|
-
This library adds support for returning errors to clients using the [`application/problem+json`](https://tools.ietf.org/html/rfc7231) media type.
|
546
|
+
This library adds support for returning errors to clients using the [`application/problem+json`](https://tools.ietf.org/html/rfc7231) media type.
|
547
|
+
You can catch and transform application errors by adding an `output_error` call before `freeze_io!`:
|
535
548
|
|
536
549
|
```ruby
|
537
550
|
class BookController < ActionController::API
|
538
551
|
include MediaTypes::Serialization
|
539
552
|
|
540
|
-
output_error CanCan::AccessDenied do |
|
541
|
-
|
542
|
-
|
553
|
+
output_error CanCan::AccessDenied do |problem_output, error|
|
554
|
+
problem_output.title 'You do not have enough permissions to perform this action.', lang: 'en'
|
555
|
+
problem_output.title 'Je hebt geen toestemming om deze actie uit te voeren.', lang: 'nl-NL'
|
543
556
|
|
544
|
-
|
557
|
+
problem_output.status_code :forbidden
|
545
558
|
end
|
546
559
|
|
547
560
|
freeze_io!
|
@@ -550,12 +563,14 @@ class BookController < ActionController::API
|
|
550
563
|
end
|
551
564
|
```
|
552
565
|
|
553
|
-
The exception you specified will be rescued by the controller and will be displayed to the user along with a link to the shared wiki page for that error type. Feel free to add instructions there on how clients should solve this problem.
|
554
|
-
|
566
|
+
The exception you specified will be rescued by the controller and will be displayed to the user along with a link to the shared wiki page for that error type. Feel free to add instructions there on how clients should solve this problem.
|
567
|
+
You can find more information at: [https://docs.delftsolutions.nl/wiki/Error](https://docs.delftsolutions.nl/wiki/Error)
|
568
|
+
If you want to override this url you can use the `problem_output.url(href)` function.
|
555
569
|
|
556
|
-
By default the `message` property of the error is used to fill the `details` field.
|
570
|
+
By default the `message` property of the error is used to fill the `details` field.
|
571
|
+
You can override this by using the `problem_output.override_details(description, lang:)` function.
|
557
572
|
|
558
|
-
Custom attributes can be added using the `
|
573
|
+
Custom attributes can be added using the `problem_output.attribute(name, value)` function.
|
559
574
|
|
560
575
|
### Related
|
561
576
|
|
@@ -581,35 +596,47 @@ Either validator or unvalidated must be used while defining a serializer.
|
|
581
596
|
|
582
597
|
#### `output( view:, version:, versions: ) do |obj, version, context|`
|
583
598
|
|
584
|
-
Defines a serialization block. Either version or versions can be set.
|
599
|
+
Defines a serialization block. Either version or versions can be set.
|
600
|
+
View should be a symbol or unset.
|
585
601
|
|
586
|
-
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
602
|
+
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
603
|
+
When using the controller integration, context is the current controller.
|
587
604
|
|
588
605
|
The block should return an object to convert into JSON.
|
589
606
|
|
590
607
|
#### `output_raw( view:, version:, versions: ) do |obj, version, context|`
|
591
608
|
|
592
|
-
This has the same behavior as `output` but should return a string instead of an object.
|
609
|
+
This has the same behavior as `output` but should return a string instead of an object.
|
610
|
+
Output is not validated.
|
593
611
|
|
594
612
|
#### `output_alias( media_type_identifier, view:, hide_variant: false )`
|
595
613
|
|
596
|
-
Defines a legacy mapping. This will make the deserializer parse the media type `media_type_identifier` as if it was version `nil` of the specified view.
|
614
|
+
Defines a legacy mapping. This will make the deserializer parse the media type `media_type_identifier` as if it was version `nil` of the specified view.
|
615
|
+
If `view` is undefined it will use the output serializer without a view defined.
|
597
616
|
|
598
|
-
Response will have a content type equal to `[media_type_identifier]; variant=[mapped_media_type_identifier]`.
|
617
|
+
Response will have a content type equal to `[media_type_identifier]; variant=[mapped_media_type_identifier]`.
|
618
|
+
If `hide_variant:` is true, the content type emitted will only be `[media_type_identifier]`.
|
619
|
+
|
620
|
+
> You cannot alias a _versioned_ media type, otherwise it would be easy to later break the definition by changing the version it aliases.
|
599
621
|
|
600
622
|
#### `output_alias_optional( media_type_identifier, view:, hide_variant: false )`
|
601
623
|
|
602
|
-
Has the same behavior as `output_alias` but can be used by multiple serializers.
|
624
|
+
Has the same behavior as `output_alias` but can be used by multiple serializers.
|
625
|
+
The serializer that is loaded last in the controller 'wins' control over this media type identifier.
|
626
|
+
If any of the serializers have an `output_alias` defined with the same media type identifier that one will win instead.
|
603
627
|
|
604
628
|
Response will have a content type equal to `[media_type_identifier]; variant=[mapped_media_type_identifier]`. If `hide_variant:` is true, the content type emitted will only be `[media_type_identifier]`.
|
605
629
|
|
606
630
|
#### `input( view:, version:, versions: ) do |obj, version, context|`
|
607
631
|
|
608
|
-
Defines a deserialization block. Either version or versions can be set.
|
632
|
+
Defines a deserialization block. Either version or versions can be set.
|
633
|
+
View should be a symbol or unset.
|
609
634
|
|
610
|
-
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
635
|
+
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
636
|
+
When using the controller integration, context is the current controller.
|
611
637
|
|
612
|
-
The block should return the internal representation of the object.
|
638
|
+
The block should return the internal representation of the object.
|
639
|
+
Best practise is to make sure not to change state in this function but to leave that up to the controller.
|
613
640
|
|
614
641
|
#### `input_raw( view:, version:, versions: ) do |bytes, version, context|`
|
615
642
|
|
@@ -617,11 +644,17 @@ This has the same behavior as `input` but takes in raw data. Input is not valida
|
|
617
644
|
|
618
645
|
#### `input_alias( media_type_identifier, view: )`
|
619
646
|
|
620
|
-
Defines a legacy mapping.
|
647
|
+
Defines a legacy mapping.
|
648
|
+
This will make the serializer parse the media type `media_type_identifier` as if it was version `nil` of the specified view.
|
649
|
+
If view is undefined it will use the input serializer without a view defined.
|
650
|
+
|
651
|
+
> You cannot alias a _versioned_ media type, otherwise it would be easy to later break the definition by changing the version it aliases.
|
621
652
|
|
622
653
|
#### `input_alias_optional( media_type_identifier, view: )`
|
623
654
|
|
624
|
-
Has the same behavior as `input_alias` but can be used by multiple serializers.
|
655
|
+
Has the same behavior as `input_alias` but can be used by multiple serializers.
|
656
|
+
The serializer that is loaded last in the controller 'wins' control over this media type identifier.
|
657
|
+
If any of the serializers have an `input_alias` defined with the same media type identifier that one will win instead.
|
625
658
|
|
626
659
|
#### `disable_wildcards`
|
627
660
|
|
@@ -633,13 +666,15 @@ The following methods are available within an `output ... do` block.
|
|
633
666
|
|
634
667
|
#### `attribute( key, value = {} ) do`
|
635
668
|
|
636
|
-
Sets a value for the given key.
|
669
|
+
Sets a value for the given key.
|
670
|
+
If a block is given, any `attribute`, `link`, `collection` and `index` statements are run in context of `value`.
|
637
671
|
|
638
672
|
Returns the built up context so far.
|
639
673
|
|
640
674
|
#### `link( rel, href:, emit_header: true, **attributes )`
|
641
675
|
|
642
|
-
Adds a `_link` block to the current context. Also adds the specified link to the HTTP Link header.
|
676
|
+
Adds a `_link` block to the current context. Also adds the specified link to the HTTP Link header.
|
677
|
+
`attributes` allows passing in custom attributes.
|
643
678
|
|
644
679
|
If `emit_header` is `true` the link will also be emitted as a http header.
|
645
680
|
|
@@ -660,7 +695,9 @@ Returns the built up context so far.
|
|
660
695
|
|
661
696
|
#### `hidden do`
|
662
697
|
|
663
|
-
Sometimes you want to add links without actually modifying the object.
|
698
|
+
Sometimes you want to add links without actually modifying the object.
|
699
|
+
Calls to `attribute`, `link`, `index`, `collection` made inside this block won't modify the context.
|
700
|
+
Any calls to link will only set the HTTP Link header.
|
664
701
|
|
665
702
|
Returns the unmodified context.
|
666
703
|
|
@@ -684,7 +721,8 @@ These functions are available during the controller definition if you add `inclu
|
|
684
721
|
|
685
722
|
#### `allow_output_serializer( serializer, views: nil, **filters )`
|
686
723
|
|
687
|
-
Configure the controller to allow the client to request responses emitted by the specified serializer.
|
724
|
+
Configure the controller to allow the client to request responses emitted by the specified serializer.
|
725
|
+
Optionally allows you to specify which views to allow by passing an array in the views parameter.
|
688
726
|
|
689
727
|
Accepts the same filters as `before_action`.
|
690
728
|
|
@@ -692,9 +730,11 @@ Accepts the same filters as `before_action`.
|
|
692
730
|
|
693
731
|
Allows falling back to the default Rails view rendering when the client asks for the media type in the `as:` parameter or `text/html` if `as:` is unset.
|
694
732
|
|
695
|
-
The `Content-Type` of the response will be `text/html` if the `as:` parameter is unset.
|
733
|
+
The `Content-Type` of the response will be `text/html` if the `as:` parameter is unset.
|
734
|
+
If the `as:` parameter is set, it will include it in the variant parameter: `text/html; variant=application/vnd.xpbytes.borderless`.
|
696
735
|
|
697
|
-
Accepts the same filters as `before_action`.
|
736
|
+
Accepts the same filters as `before_action`.
|
737
|
+
You can set the template to use using the `view:` parameter.
|
698
738
|
|
699
739
|
#### `allow_output_docs( description, **filters )`
|
700
740
|
|
@@ -704,7 +744,8 @@ Accepts the same filters as `before_action`.
|
|
704
744
|
|
705
745
|
#### `allow_input_serializer( serializer, views: nil, **filters )`
|
706
746
|
|
707
|
-
Configure the controller to allow the client to send bodies with a `Content-Type` that can be deserialized using the specified serializer.
|
747
|
+
Configure the controller to allow the client to send bodies with a `Content-Type` that can be deserialized using the specified serializer.
|
748
|
+
Optionally allows you to specify which views to allow by passing an array in the views parameter.
|
708
749
|
|
709
750
|
Accepts the same filters as `before_action`.
|
710
751
|
|
@@ -738,7 +779,8 @@ Enables rendering the api viewer when adding the `api_viewer=last` query paramet
|
|
738
779
|
|
739
780
|
#### `freeze_io!(**filter_opts)`
|
740
781
|
|
741
|
-
Registers serialization and deserialization in the controller.
|
782
|
+
Registers serialization and deserialization in the controller.
|
783
|
+
This function must be called before using the controller.
|
742
784
|
|
743
785
|
### Controller usage
|
744
786
|
|
@@ -746,7 +788,8 @@ These functions are available during method execution in the controller.
|
|
746
788
|
|
747
789
|
#### `render_media( obj, serializers: nil, not_acceptable_serializer: nil, **options ) do`
|
748
790
|
|
749
|
-
Serializes an object and renders it using the appropriate content type.
|
791
|
+
Serializes an object and renders it using the appropriate content type.
|
792
|
+
Options are passed through to the controller `render` function. Allows you to specify different objects to different serializers using a block:
|
750
793
|
|
751
794
|
```ruby
|
752
795
|
render_media do
|
@@ -757,13 +800,15 @@ render_media do
|
|
757
800
|
end
|
758
801
|
```
|
759
802
|
|
760
|
-
Warning
|
803
|
+
**Warning**: this block can be called multiple times when used together with recursive serializers like the API viewer.
|
804
|
+
Try to _avoid changing state_ in this block.
|
761
805
|
|
762
806
|
If you want to render with different serializers than defined in the controller you can pass an array of serializers in the `serializers` property.
|
763
807
|
|
764
808
|
If you want to override the serializer that is used to render the response when no acceptable Content-Type could be negotiated you can pass the desired serializer in the `not_acceptable_serializer` property.
|
765
809
|
|
766
|
-
This method throws a `MediaTypes::Serialization::OutputValidationFailedError` error if the output does not conform to the format defined by the configured validator.
|
810
|
+
This method throws a `MediaTypes::Serialization::OutputValidationFailedError` error if the output does not conform to the format defined by the configured validator.
|
811
|
+
Best practise is to return a 500 error to the client.
|
767
812
|
|
768
813
|
If no acceptable Content-Type could be negotiated the response will be rendered using the serialized defined by the class `not_acceptable_serializer` function or by the `not_acceptable_serializer` property.
|
769
814
|
|
@@ -805,12 +850,11 @@ HERE
|
|
805
850
|
|
806
851
|
## Development
|
807
852
|
|
808
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
809
|
-
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
853
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
854
|
+
Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
810
855
|
|
811
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
812
|
-
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
813
|
-
push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
856
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
857
|
+
To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
814
858
|
|
815
859
|
## Contributing
|
816
860
|
|
@@ -184,7 +184,7 @@ module MediaTypes
|
|
184
184
|
end
|
185
185
|
end
|
186
186
|
|
187
|
-
def allow_output_html(as: nil, view: nil, layout: nil, **filter_opts)
|
187
|
+
def allow_output_html(as: nil, view: nil, layout: nil, formats: [:html], variants: nil, **filter_opts)
|
188
188
|
before_action(**filter_opts) do
|
189
189
|
raise SerializersAlreadyFrozenError if defined? @serialization_frozen
|
190
190
|
|
@@ -197,19 +197,13 @@ module MediaTypes
|
|
197
197
|
validator = FakeValidator.new(as.nil? ? 'text/html' : as)
|
198
198
|
|
199
199
|
block = lambda { |_, _, controller|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
if view.nil?
|
208
|
-
controller.render_to_string(layout: layout)
|
209
|
-
else
|
210
|
-
controller.render_to_string(template: view, layout: layout)
|
211
|
-
end
|
212
|
-
end
|
200
|
+
options = {}
|
201
|
+
options[:layout] = layout unless layout.nil?
|
202
|
+
options[:template] = view unless view.nil?
|
203
|
+
options[:formats] = formats unless formats.nil?
|
204
|
+
options[:variants] = variants unless variants.nil?
|
205
|
+
|
206
|
+
controller.render_to_string(**options)
|
213
207
|
}
|
214
208
|
|
215
209
|
html_registration.register_block(nil, validator, nil, block, true, wildcards: true)
|
@@ -342,11 +336,6 @@ module MediaTypes
|
|
342
336
|
end
|
343
337
|
# rubocop:enable Metrics/BlockLength
|
344
338
|
|
345
|
-
included do
|
346
|
-
protected
|
347
|
-
|
348
|
-
end
|
349
|
-
|
350
339
|
protected
|
351
340
|
|
352
341
|
def serialize(victim, media_type, serializer: Object.new, links: [], vary: ['Accept'])
|
@@ -366,6 +355,7 @@ module MediaTypes
|
|
366
355
|
if obj == MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED && block.nil?
|
367
356
|
raise 'render_media was called without an object. Please provide one or supply a block to match the serializer.'
|
368
357
|
end
|
358
|
+
|
369
359
|
obj = nil if obj == MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED
|
370
360
|
|
371
361
|
raise SerializersNotFrozenError unless defined? @serialization_frozen
|
@@ -395,10 +385,17 @@ module MediaTypes
|
|
395
385
|
selector.instance_exec(&block)
|
396
386
|
|
397
387
|
raise UnmatchedSerializerError, serializer unless selector.matched
|
388
|
+
|
398
389
|
obj = selector.value
|
399
390
|
end
|
400
391
|
|
401
|
-
serialization_render_resolved(
|
392
|
+
serialization_render_resolved(
|
393
|
+
obj: obj,
|
394
|
+
serializer: serializer,
|
395
|
+
identifier: identifier,
|
396
|
+
registrations: registration,
|
397
|
+
options: options
|
398
|
+
)
|
402
399
|
end
|
403
400
|
|
404
401
|
def deserialize(request)
|
@@ -417,6 +414,7 @@ module MediaTypes
|
|
417
414
|
raise SerializersNotFrozenError unless defined?(@serialization_frozen)
|
418
415
|
raise NoInputReceivedError if request.content_type.blank?
|
419
416
|
raise InputNotAcceptableError unless @serialization_input_registrations.has? request.content_type
|
417
|
+
|
420
418
|
@serialization_input_registrations.call(@serialization_decoded_input, request.content_type, self)
|
421
419
|
end
|
422
420
|
|
@@ -427,6 +425,7 @@ module MediaTypes
|
|
427
425
|
registration = registration.registrations[identifier]
|
428
426
|
|
429
427
|
raise 'Assertion failed, inconsistent answer from resolve_media_type' if registration.nil?
|
428
|
+
|
430
429
|
registration.serializer
|
431
430
|
end
|
432
431
|
|
@@ -434,8 +433,12 @@ module MediaTypes
|
|
434
433
|
|
435
434
|
def resolve_media_type(request, registration, allow_last: true)
|
436
435
|
if defined? @serialization_override_accept
|
437
|
-
|
436
|
+
if allow_last && @serialization_override_accept == 'last'
|
437
|
+
@serialization_override_accept = registration.registrations.keys.last
|
438
|
+
end
|
439
|
+
|
438
440
|
return nil unless registration.has? @serialization_override_accept
|
441
|
+
|
439
442
|
return @serialization_override_accept
|
440
443
|
end
|
441
444
|
|
@@ -483,7 +486,10 @@ module MediaTypes
|
|
483
486
|
input_is_allowed = @serialization_input_registrations.has? request.content_type unless request.content_type.blank?
|
484
487
|
|
485
488
|
unless input_is_allowed || all_allowed
|
486
|
-
serializers = @serialization_unsupported_media_type_serializer || [
|
489
|
+
serializers = @serialization_unsupported_media_type_serializer || [
|
490
|
+
MediaTypes::Serialization::Serializers::ProblemSerializer,
|
491
|
+
MediaTypes::Serialization::Serializers::FallbackUnsupportedMediaTypeSerializer
|
492
|
+
]
|
487
493
|
registrations = SerializationRegistration.new(:output)
|
488
494
|
serializers.each do |s|
|
489
495
|
registrations = registrations.merge(s.outputs_for(views: [nil, :html]))
|
@@ -511,7 +517,10 @@ module MediaTypes
|
|
511
517
|
input_data = request.body.read
|
512
518
|
@serialization_decoded_input = @serialization_input_registrations.decode(input_data, request.content_type, self)
|
513
519
|
rescue InputValidationFailedError => e
|
514
|
-
serializers = @serialization_input_validation_failed_serializer || [
|
520
|
+
serializers = @serialization_input_validation_failed_serializer || [
|
521
|
+
MediaTypes::Serialization::Serializers::ProblemSerializer,
|
522
|
+
MediaTypes::Serialization::Serializers::InputValidationErrorSerializer
|
523
|
+
]
|
515
524
|
registrations = SerializationRegistration.new(:output)
|
516
525
|
serializers.each do |s|
|
517
526
|
registrations = registrations.merge(s.outputs_for(views: [nil, :html]))
|
@@ -557,7 +566,13 @@ module MediaTypes
|
|
557
566
|
actions: @serialization_available_serializers,
|
558
567
|
}
|
559
568
|
|
560
|
-
serialization_render_resolved
|
569
|
+
serialization_render_resolved(
|
570
|
+
obj: input,
|
571
|
+
serializer: description_serializer,
|
572
|
+
identifier: endpoint_matched_identifier,
|
573
|
+
registrations: @serialization_output_registrations,
|
574
|
+
options: {}
|
575
|
+
)
|
561
576
|
return
|
562
577
|
end
|
563
578
|
|
@@ -106,22 +106,22 @@ module MediaTypes
|
|
106
106
|
validator = serializer_validator.view(view)
|
107
107
|
victim_identifier = validator.identifier
|
108
108
|
|
109
|
-
serializer_input_registration.register_alias(self, media_type_identifier, victim_identifier, false)
|
109
|
+
serializer_input_registration.register_alias(self, media_type_identifier, victim_identifier, false, true, wildcards: false)
|
110
110
|
end
|
111
111
|
|
112
112
|
def input_alias_optional(media_type_identifier, view: nil)
|
113
113
|
validator = serializer_validator.view(view)
|
114
114
|
victim_identifier = validator.identifier
|
115
115
|
|
116
|
-
serializer_input_registration.register_alias(self, media_type_identifier, victim_identifier, true)
|
116
|
+
serializer_input_registration.register_alias(self, media_type_identifier, victim_identifier, true, true, wildcards: false)
|
117
117
|
end
|
118
118
|
|
119
|
-
def serialize(victim, media_type_identifier, context
|
119
|
+
def serialize(victim, media_type_identifier, context:, dsl: nil, raw: nil)
|
120
120
|
dsl ||= SerializationDSL.new(self, context: context)
|
121
121
|
serializer_output_registration.call(victim, media_type_identifier.to_s, context, dsl: dsl, raw: raw)
|
122
122
|
end
|
123
123
|
|
124
|
-
def deserialize(victim, media_type_identifier, context)
|
124
|
+
def deserialize(victim, media_type_identifier, context:)
|
125
125
|
serializer_input_registration.call(victim, media_type_identifier, context)
|
126
126
|
end
|
127
127
|
|
@@ -56,7 +56,7 @@ module MediaTypes
|
|
56
56
|
array.each do |e|
|
57
57
|
child_links = []
|
58
58
|
context = SerializationDSL.new(__getobj__, child_links, context: @serialization_context)
|
59
|
-
serializer.serialize(e, identifier, @serialization_context, dsl: context)
|
59
|
+
serializer.serialize(e, identifier, context: @serialization_context, dsl: context)
|
60
60
|
|
61
61
|
self_links = child_links.select { |l| l[:rel] == :self }
|
62
62
|
raise NoSelfLinkProvidedError, identifier unless self_links.any?
|
@@ -79,7 +79,7 @@ module MediaTypes
|
|
79
79
|
|
80
80
|
array.each do |e|
|
81
81
|
context = SerializationDSL.new(__getobj__, [], @serialization_vary, context: @serialization_context)
|
82
|
-
result = serializer.serialize(e, identifier, @serialization_context, dsl: context, raw: true)
|
82
|
+
result = serializer.serialize(e, identifier, context: @serialization_context, dsl: context, raw: true)
|
83
83
|
|
84
84
|
result = block.call(result) unless block.nil?
|
85
85
|
|
@@ -105,7 +105,7 @@ module MediaTypes
|
|
105
105
|
def emit
|
106
106
|
serialization_dsl_result
|
107
107
|
end
|
108
|
-
|
108
|
+
|
109
109
|
def object(&block)
|
110
110
|
context = SerializationDSL.new(__getobj__, @serialization_links, @serialization_vary, context: @serialization_context)
|
111
111
|
context.instance_exec(&block)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: media_types-serialization
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derk-Jan Karrenbeld
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2021-
|
12
|
+
date: 2021-08-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: actionpack
|