media_types-serialization 1.2.0 → 1.3.4
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/CHANGELOG.md +26 -0
- data/Gemfile.lock +137 -137
- data/README.md +133 -59
- data/lib/media_types/serialization.rb +44 -26
- data/lib/media_types/serialization/base.rb +90 -25
- data/lib/media_types/serialization/fake_validator.rb +1 -0
- data/lib/media_types/serialization/serialization_dsl.rb +3 -3
- data/lib/media_types/serialization/serialization_registration.rb +2 -2
- data/lib/media_types/serialization/version.rb +1 -1
- data/media_types-serialization.gemspec +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 737a38bc10cd0c3aff8fa9bc33c3c192098709eb331f7c35706840410ff3d280
|
|
4
|
+
data.tar.gz: d6311d9a1b27329e4164cb7bf3b8e839ce96419b05e9a9e42d033d7ba2942a50
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c6fad7b09ecc516290fb5e0393ee5a790c128a75402cdb977c396b6dac01b30748b63f5631b001b7eaa9d9c1b8007e814200d9be7766afa757d1c93785bc34f8
|
|
7
|
+
data.tar.gz: ea95bb41414b2125ac3af7efe42ff9c5e521f36a7bae2930760dd52fdee3e58e1175e5aaa8f03d3eb27bf5022d089f0542f4bc51b418cee05ae3724ba3756779
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.4
|
|
4
|
+
|
|
5
|
+
- Same as `1.3.3`
|
|
6
|
+
|
|
7
|
+
## 1.3.3
|
|
8
|
+
|
|
9
|
+
- 🐛 Fix override suffix not being picked up correctly
|
|
10
|
+
- 🐛 Fix inability to override suffix for aliases
|
|
11
|
+
- 🐛 Fix inability to override suffix for raw
|
|
12
|
+
- 🐛 Fix default suffix for raw
|
|
13
|
+
|
|
14
|
+
## 1.3.2
|
|
15
|
+
|
|
16
|
+
- 🐛 Fix override suffix not returning self or new
|
|
17
|
+
|
|
18
|
+
## 1.3.1
|
|
19
|
+
|
|
20
|
+
- 🐛 Fix api viewer
|
|
21
|
+
- 🐛 Fix `output_raw` suffix (`+json` needs to be `''`)
|
|
22
|
+
|
|
23
|
+
## 1.3.0
|
|
24
|
+
|
|
25
|
+
- ✨ Add `formats:` to `output_html` and default it to `[:html]`, so rails behaves
|
|
26
|
+
- 🐛 Fix stale references to `render media:`
|
|
27
|
+
- 🐛 Fix inconsistent `context:` passing for `Serializer.serialize`
|
|
28
|
+
|
|
3
29
|
## 1.2.0
|
|
4
30
|
|
|
5
31
|
- ✨ 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.
|
|
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.
|
|
60
|
-
activesupport (>=
|
|
61
|
-
i18n (1.8.10)
|
|
62
|
-
concurrent-ruby (~> 1.0)
|
|
63
|
-
loofah (2.
|
|
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
|
|
70
|
-
method_source (1.0.0)
|
|
71
|
-
mini_mime (1.1.0)
|
|
72
|
-
minitest (5.14.4)
|
|
73
|
-
nio4r (2.5.
|
|
74
|
-
nokogiri (1.
|
|
75
|
-
racc (~> 1.4)
|
|
76
|
-
nokogiri (1.
|
|
77
|
-
racc (~> 1.4)
|
|
78
|
-
oj (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
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
media_types-serialization (1.3.4)
|
|
5
|
+
actionpack (>= 4.0.0)
|
|
6
|
+
activesupport (>= 4.0.0)
|
|
7
|
+
media_types (>= 2.1.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.5.2)
|
|
60
|
+
activesupport (>= 5.0)
|
|
61
|
+
i18n (1.8.10)
|
|
62
|
+
concurrent-ruby (~> 1.0)
|
|
63
|
+
loofah (2.12.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.1.0)
|
|
70
|
+
method_source (1.0.0)
|
|
71
|
+
mini_mime (1.1.0)
|
|
72
|
+
minitest (5.14.4)
|
|
73
|
+
nio4r (2.5.8)
|
|
74
|
+
nokogiri (1.12.3-x64-mingw32)
|
|
75
|
+
racc (~> 1.4)
|
|
76
|
+
nokogiri (1.12.3-x86_64-linux)
|
|
77
|
+
racc (~> 1.4)
|
|
78
|
+
oj (3.13.1)
|
|
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
|
|
|
@@ -563,7 +578,7 @@ Custom attributes can be added using the `p.attribute(name, value)` function.
|
|
|
563
578
|
|
|
564
579
|
## API
|
|
565
580
|
|
|
566
|
-
### Serializer definition
|
|
581
|
+
### Serializer class definition
|
|
567
582
|
|
|
568
583
|
These methods become available during class definition if you inherit from `MediaTypes::Serialization::Base`.
|
|
569
584
|
|
|
@@ -581,65 +596,95 @@ 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
|
+
`nil` is allowed for unversioned.
|
|
601
|
+
View should be a symbol or unset.
|
|
585
602
|
|
|
586
|
-
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
|
603
|
+
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
|
604
|
+
When using the controller integration, context is the current controller.
|
|
587
605
|
|
|
588
606
|
The block should return an object to convert into JSON.
|
|
589
607
|
|
|
590
|
-
#### `output_raw( view:, version:, versions: ) do |obj, version, context|`
|
|
608
|
+
#### `output_raw( view:, version:, versions:, suffix: ) do |obj, version, context|`
|
|
591
609
|
|
|
592
|
-
This has the same behavior as `output` but should return a string instead of an object.
|
|
610
|
+
This has the same behavior as `output` but should return a string instead of an object.
|
|
611
|
+
Output is not validated.
|
|
612
|
+
By default, `input_raw` is expected to _not_ be JSON.
|
|
613
|
+
Override `suffix` with `:json` if it _is_ JSON.
|
|
593
614
|
|
|
594
|
-
#### `output_alias( media_type_identifier, view:, hide_variant: false )`
|
|
615
|
+
#### `output_alias( media_type_identifier, view:, hide_variant: false, suffix: '~' )`
|
|
595
616
|
|
|
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.
|
|
617
|
+
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.
|
|
618
|
+
If `view` is undefined it will use the output serializer without a view defined.
|
|
619
|
+
By default, suffix is `:json` if `media_type_identifier` is a JSON type.
|
|
597
620
|
|
|
598
|
-
Response will have a content type equal to `[media_type_identifier]; variant=[mapped_media_type_identifier]`.
|
|
621
|
+
Response will have a content type equal to `[media_type_identifier]; variant=[mapped_media_type_identifier]`.
|
|
622
|
+
If `hide_variant:` is true, the content type emitted will only be `[media_type_identifier]`.
|
|
623
|
+
|
|
624
|
+
> You cannot alias a _versioned_ media type, otherwise it would be easy to later break the definition by changing the version it aliases.
|
|
599
625
|
|
|
600
|
-
#### `output_alias_optional( media_type_identifier, view:, hide_variant: false )`
|
|
626
|
+
#### `output_alias_optional( media_type_identifier, view:, hide_variant: false, suffix: '~' )`
|
|
601
627
|
|
|
602
|
-
Has the same behavior as `output_alias` but can be used by multiple serializers.
|
|
628
|
+
Has the same behavior as `output_alias` but can be used by multiple serializers.
|
|
629
|
+
The serializer that is loaded last in the controller 'wins' control over this media type identifier.
|
|
630
|
+
If any of the serializers have an `output_alias` defined with the same media type identifier that one will win instead.
|
|
631
|
+
By default, suffix is `:json` if `media_type_identifier` is a JSON type.
|
|
603
632
|
|
|
604
633
|
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
634
|
|
|
606
635
|
#### `input( view:, version:, versions: ) do |obj, version, context|`
|
|
607
636
|
|
|
608
|
-
Defines a deserialization block. Either version or versions can be set.
|
|
637
|
+
Defines a deserialization block. Either version or versions can be set.
|
|
638
|
+
View should be a symbol or unset.
|
|
609
639
|
|
|
610
|
-
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
|
640
|
+
Obj is the object to be serialized, version is the negotiated version and context is the context passed in from the serialize function.
|
|
641
|
+
When using the controller integration, context is the current controller.
|
|
611
642
|
|
|
612
|
-
The block should return the internal representation of the object.
|
|
643
|
+
The block should return the internal representation of the object.
|
|
644
|
+
Best practise is to make sure not to change state in this function but to leave that up to the controller.
|
|
613
645
|
|
|
614
|
-
#### `input_raw( view:, version:, versions: ) do |bytes, version, context|`
|
|
646
|
+
#### `input_raw( view:, version:, versions:, suffix: nil ) do |bytes, version, context|`
|
|
615
647
|
|
|
616
|
-
This has the same behavior as `input` but takes in raw data.
|
|
648
|
+
This has the same behavior as `input` but takes in raw data.
|
|
649
|
+
Input is not validated.
|
|
650
|
+
By default, `input_raw` is expected to _not_ be JSON.
|
|
651
|
+
Override `suffix` with `:json` if it _is_ JSON.
|
|
617
652
|
|
|
618
|
-
#### `input_alias( media_type_identifier, view: )`
|
|
653
|
+
#### `input_alias( media_type_identifier, view:, suffix: '~' )`
|
|
619
654
|
|
|
620
|
-
Defines a legacy mapping.
|
|
655
|
+
Defines a legacy mapping.
|
|
656
|
+
This will make the serializer parse the media type `media_type_identifier` as if it was version `nil` of the specified view.
|
|
657
|
+
If view is undefined it will use the input serializer without a view defined.
|
|
658
|
+
By default, suffix is `:json` if `media_type_identifier` is a JSON type.
|
|
621
659
|
|
|
622
|
-
|
|
660
|
+
> You cannot alias a _versioned_ media type, otherwise it would be easy to later break the definition by changing the version it aliases.
|
|
623
661
|
|
|
624
|
-
|
|
662
|
+
#### `input_alias_optional( media_type_identifier, view:, suffix: '~' )`
|
|
663
|
+
|
|
664
|
+
Has the same behavior as `input_alias` but can be used by multiple serializers.
|
|
665
|
+
The serializer that is loaded last in the controller 'wins' control over this media type identifier.
|
|
666
|
+
If any of the serializers have an `input_alias` defined with the same media type identifier that one will win instead.
|
|
667
|
+
By default, suffix is `:json` if `media_type_identifier` is a JSON type.
|
|
625
668
|
|
|
626
669
|
#### `disable_wildcards`
|
|
627
670
|
|
|
628
671
|
Disables registering wildcard media types.
|
|
629
672
|
|
|
630
|
-
### Serializer definition
|
|
673
|
+
### Serializer output definition
|
|
631
674
|
|
|
632
675
|
The following methods are available within an `output ... do` block.
|
|
633
676
|
|
|
634
677
|
#### `attribute( key, value = {} ) do`
|
|
635
678
|
|
|
636
|
-
Sets a value for the given key.
|
|
679
|
+
Sets a value for the given key.
|
|
680
|
+
If a block is given, any `attribute`, `link`, `collection` and `index` statements are run in context of `value`.
|
|
637
681
|
|
|
638
682
|
Returns the built up context so far.
|
|
639
683
|
|
|
640
684
|
#### `link( rel, href:, emit_header: true, **attributes )`
|
|
641
685
|
|
|
642
|
-
Adds a `_link` block to the current context. Also adds the specified link to the HTTP Link header.
|
|
686
|
+
Adds a `_link` block to the current context. Also adds the specified link to the HTTP Link header.
|
|
687
|
+
`attributes` allows passing in custom attributes.
|
|
643
688
|
|
|
644
689
|
If `emit_header` is `true` the link will also be emitted as a http header.
|
|
645
690
|
|
|
@@ -647,12 +692,16 @@ Returns the built up context so far.
|
|
|
647
692
|
|
|
648
693
|
#### `index( array, serializer, version:, view: nil )`
|
|
649
694
|
|
|
695
|
+
> Not the same as a validator `collection`.
|
|
696
|
+
|
|
650
697
|
Adds an `_index` block to the current context. Uses the self links of the specified view to construct an index of urls to the child objects.
|
|
651
698
|
|
|
652
699
|
Returns the built up context so far.
|
|
653
700
|
|
|
654
701
|
#### `collection( array, serializer, version:, view: nil )`
|
|
655
702
|
|
|
703
|
+
> Not the same as a validator `collection`.
|
|
704
|
+
|
|
656
705
|
Adds an `_embedded` block to the current context. Uses the specified serializer to embed the child objects.
|
|
657
706
|
Optionally a block can be used to modify the output from the child serializer.
|
|
658
707
|
|
|
@@ -660,7 +709,9 @@ Returns the built up context so far.
|
|
|
660
709
|
|
|
661
710
|
#### `hidden do`
|
|
662
711
|
|
|
663
|
-
Sometimes you want to add links without actually modifying the object.
|
|
712
|
+
Sometimes you want to add links without actually modifying the object.
|
|
713
|
+
Calls to `attribute`, `link`, `index`, `collection` made inside this block won't modify the context.
|
|
714
|
+
Any calls to link will only set the HTTP Link header.
|
|
664
715
|
|
|
665
716
|
Returns the unmodified context.
|
|
666
717
|
|
|
@@ -674,9 +725,25 @@ Returns the built up context so far.
|
|
|
674
725
|
|
|
675
726
|
Runs a block in a new context and returns the result
|
|
676
727
|
|
|
728
|
+
> Most common use-case is emitting from an enumerable.
|
|
729
|
+
>
|
|
730
|
+
> ```ruby
|
|
731
|
+
> results = [item, item, item].map do |current_item|
|
|
732
|
+
> object do
|
|
733
|
+
> attribute :foo, current_item.bar
|
|
734
|
+
> end
|
|
735
|
+
> end
|
|
736
|
+
>
|
|
737
|
+
> attribute :items, results
|
|
738
|
+
> ```
|
|
739
|
+
|
|
677
740
|
#### `render_view( view, context:, **args)`
|
|
678
741
|
|
|
679
|
-
Can be used to render a view.
|
|
742
|
+
Can be used to render a view.
|
|
743
|
+
You can set local variables in the view by assigning a hash to the `assigns:` parameter.
|
|
744
|
+
Returns a `string`
|
|
745
|
+
|
|
746
|
+
> When possible, prefer `output_raw` with `context.class.render(params)`
|
|
680
747
|
|
|
681
748
|
### Controller definition
|
|
682
749
|
|
|
@@ -684,7 +751,8 @@ These functions are available during the controller definition if you add `inclu
|
|
|
684
751
|
|
|
685
752
|
#### `allow_output_serializer( serializer, views: nil, **filters )`
|
|
686
753
|
|
|
687
|
-
Configure the controller to allow the client to request responses emitted by the specified serializer.
|
|
754
|
+
Configure the controller to allow the client to request responses emitted by the specified serializer.
|
|
755
|
+
Optionally allows you to specify which views to allow by passing an array in the views parameter.
|
|
688
756
|
|
|
689
757
|
Accepts the same filters as `before_action`.
|
|
690
758
|
|
|
@@ -692,9 +760,11 @@ Accepts the same filters as `before_action`.
|
|
|
692
760
|
|
|
693
761
|
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
762
|
|
|
695
|
-
The `Content-Type` of the response will be `text/html` if the `as:` parameter is unset.
|
|
763
|
+
The `Content-Type` of the response will be `text/html` if the `as:` parameter is unset.
|
|
764
|
+
If the `as:` parameter is set, it will include it in the variant parameter: `text/html; variant=application/vnd.xpbytes.borderless`.
|
|
696
765
|
|
|
697
|
-
Accepts the same filters as `before_action`.
|
|
766
|
+
Accepts the same filters as `before_action`.
|
|
767
|
+
You can set the template to use using the `view:` parameter.
|
|
698
768
|
|
|
699
769
|
#### `allow_output_docs( description, **filters )`
|
|
700
770
|
|
|
@@ -704,7 +774,8 @@ Accepts the same filters as `before_action`.
|
|
|
704
774
|
|
|
705
775
|
#### `allow_input_serializer( serializer, views: nil, **filters )`
|
|
706
776
|
|
|
707
|
-
Configure the controller to allow the client to send bodies with a `Content-Type` that can be deserialized using the specified serializer.
|
|
777
|
+
Configure the controller to allow the client to send bodies with a `Content-Type` that can be deserialized using the specified serializer.
|
|
778
|
+
Optionally allows you to specify which views to allow by passing an array in the views parameter.
|
|
708
779
|
|
|
709
780
|
Accepts the same filters as `before_action`.
|
|
710
781
|
|
|
@@ -738,7 +809,8 @@ Enables rendering the api viewer when adding the `api_viewer=last` query paramet
|
|
|
738
809
|
|
|
739
810
|
#### `freeze_io!(**filter_opts)`
|
|
740
811
|
|
|
741
|
-
Registers serialization and deserialization in the controller.
|
|
812
|
+
Registers serialization and deserialization in the controller.
|
|
813
|
+
This function must be called before using the controller.
|
|
742
814
|
|
|
743
815
|
### Controller usage
|
|
744
816
|
|
|
@@ -746,7 +818,8 @@ These functions are available during method execution in the controller.
|
|
|
746
818
|
|
|
747
819
|
#### `render_media( obj, serializers: nil, not_acceptable_serializer: nil, **options ) do`
|
|
748
820
|
|
|
749
|
-
Serializes an object and renders it using the appropriate content type.
|
|
821
|
+
Serializes an object and renders it using the appropriate content type.
|
|
822
|
+
Options are passed through to the controller `render` function. Allows you to specify different objects to different serializers using a block:
|
|
750
823
|
|
|
751
824
|
```ruby
|
|
752
825
|
render_media do
|
|
@@ -757,13 +830,15 @@ render_media do
|
|
|
757
830
|
end
|
|
758
831
|
```
|
|
759
832
|
|
|
760
|
-
Warning
|
|
833
|
+
**Warning**: this block can be called multiple times when used together with recursive serializers like the API viewer.
|
|
834
|
+
Try to _avoid changing state_ in this block.
|
|
761
835
|
|
|
762
836
|
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
837
|
|
|
764
838
|
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
839
|
|
|
766
|
-
This method throws a `MediaTypes::Serialization::OutputValidationFailedError` error if the output does not conform to the format defined by the configured validator.
|
|
840
|
+
This method throws a `MediaTypes::Serialization::OutputValidationFailedError` error if the output does not conform to the format defined by the configured validator.
|
|
841
|
+
Best practise is to return a 500 error to the client.
|
|
767
842
|
|
|
768
843
|
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
844
|
|
|
@@ -805,12 +880,11 @@ HERE
|
|
|
805
880
|
|
|
806
881
|
## Development
|
|
807
882
|
|
|
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.
|
|
883
|
+
After checking out the repo, run `bin/setup` to install dependencies.
|
|
884
|
+
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
885
|
|
|
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).
|
|
886
|
+
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
887
|
+
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
888
|
|
|
815
889
|
## Contributing
|
|
816
890
|
|
|
@@ -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'])
|
|
@@ -356,7 +345,10 @@ module MediaTypes
|
|
|
356
345
|
|
|
357
346
|
MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED = ::Object.new
|
|
358
347
|
|
|
359
|
-
def render_media(obj = MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED,
|
|
348
|
+
def render_media(obj = MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED, **options, &block)
|
|
349
|
+
serializers = options.delete(:serializers)
|
|
350
|
+
not_acceptable_serializer = options.delete(:not_acceptable_serializer)
|
|
351
|
+
|
|
360
352
|
if obj == MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED && options.keys.any? && !block
|
|
361
353
|
# options is too greedy :(
|
|
362
354
|
obj = options
|
|
@@ -366,6 +358,7 @@ module MediaTypes
|
|
|
366
358
|
if obj == MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED && block.nil?
|
|
367
359
|
raise 'render_media was called without an object. Please provide one or supply a block to match the serializer.'
|
|
368
360
|
end
|
|
361
|
+
|
|
369
362
|
obj = nil if obj == MEDIA_TYPES_SERIALIZATION_OBJ_IS_UNDEFINED
|
|
370
363
|
|
|
371
364
|
raise SerializersNotFrozenError unless defined? @serialization_frozen
|
|
@@ -395,10 +388,17 @@ module MediaTypes
|
|
|
395
388
|
selector.instance_exec(&block)
|
|
396
389
|
|
|
397
390
|
raise UnmatchedSerializerError, serializer unless selector.matched
|
|
391
|
+
|
|
398
392
|
obj = selector.value
|
|
399
393
|
end
|
|
400
394
|
|
|
401
|
-
serialization_render_resolved(
|
|
395
|
+
serialization_render_resolved(
|
|
396
|
+
obj: obj,
|
|
397
|
+
serializer: serializer,
|
|
398
|
+
identifier: identifier,
|
|
399
|
+
registrations: registration,
|
|
400
|
+
options: options
|
|
401
|
+
)
|
|
402
402
|
end
|
|
403
403
|
|
|
404
404
|
def deserialize(request)
|
|
@@ -417,6 +417,7 @@ module MediaTypes
|
|
|
417
417
|
raise SerializersNotFrozenError unless defined?(@serialization_frozen)
|
|
418
418
|
raise NoInputReceivedError if request.content_type.blank?
|
|
419
419
|
raise InputNotAcceptableError unless @serialization_input_registrations.has? request.content_type
|
|
420
|
+
|
|
420
421
|
@serialization_input_registrations.call(@serialization_decoded_input, request.content_type, self)
|
|
421
422
|
end
|
|
422
423
|
|
|
@@ -427,6 +428,7 @@ module MediaTypes
|
|
|
427
428
|
registration = registration.registrations[identifier]
|
|
428
429
|
|
|
429
430
|
raise 'Assertion failed, inconsistent answer from resolve_media_type' if registration.nil?
|
|
431
|
+
|
|
430
432
|
registration.serializer
|
|
431
433
|
end
|
|
432
434
|
|
|
@@ -434,8 +436,12 @@ module MediaTypes
|
|
|
434
436
|
|
|
435
437
|
def resolve_media_type(request, registration, allow_last: true)
|
|
436
438
|
if defined? @serialization_override_accept
|
|
437
|
-
|
|
439
|
+
if allow_last && @serialization_override_accept == 'last'
|
|
440
|
+
@serialization_override_accept = registration.registrations.keys.last
|
|
441
|
+
end
|
|
442
|
+
|
|
438
443
|
return nil unless registration.has? @serialization_override_accept
|
|
444
|
+
|
|
439
445
|
return @serialization_override_accept
|
|
440
446
|
end
|
|
441
447
|
|
|
@@ -483,7 +489,10 @@ module MediaTypes
|
|
|
483
489
|
input_is_allowed = @serialization_input_registrations.has? request.content_type unless request.content_type.blank?
|
|
484
490
|
|
|
485
491
|
unless input_is_allowed || all_allowed
|
|
486
|
-
serializers = @serialization_unsupported_media_type_serializer || [
|
|
492
|
+
serializers = @serialization_unsupported_media_type_serializer || [
|
|
493
|
+
MediaTypes::Serialization::Serializers::ProblemSerializer,
|
|
494
|
+
MediaTypes::Serialization::Serializers::FallbackUnsupportedMediaTypeSerializer
|
|
495
|
+
]
|
|
487
496
|
registrations = SerializationRegistration.new(:output)
|
|
488
497
|
serializers.each do |s|
|
|
489
498
|
registrations = registrations.merge(s.outputs_for(views: [nil, :html]))
|
|
@@ -511,7 +520,10 @@ module MediaTypes
|
|
|
511
520
|
input_data = request.body.read
|
|
512
521
|
@serialization_decoded_input = @serialization_input_registrations.decode(input_data, request.content_type, self)
|
|
513
522
|
rescue InputValidationFailedError => e
|
|
514
|
-
serializers = @serialization_input_validation_failed_serializer || [
|
|
523
|
+
serializers = @serialization_input_validation_failed_serializer || [
|
|
524
|
+
MediaTypes::Serialization::Serializers::ProblemSerializer,
|
|
525
|
+
MediaTypes::Serialization::Serializers::InputValidationErrorSerializer
|
|
526
|
+
]
|
|
515
527
|
registrations = SerializationRegistration.new(:output)
|
|
516
528
|
serializers.each do |s|
|
|
517
529
|
registrations = registrations.merge(s.outputs_for(views: [nil, :html]))
|
|
@@ -557,7 +569,13 @@ module MediaTypes
|
|
|
557
569
|
actions: @serialization_available_serializers,
|
|
558
570
|
}
|
|
559
571
|
|
|
560
|
-
serialization_render_resolved
|
|
572
|
+
serialization_render_resolved(
|
|
573
|
+
obj: input,
|
|
574
|
+
serializer: description_serializer,
|
|
575
|
+
identifier: endpoint_matched_identifier,
|
|
576
|
+
registrations: @serialization_output_registrations,
|
|
577
|
+
options: {}
|
|
578
|
+
)
|
|
561
579
|
return
|
|
562
580
|
end
|
|
563
581
|
|
|
@@ -603,7 +621,7 @@ module MediaTypes
|
|
|
603
621
|
output: result,
|
|
604
622
|
links: links,
|
|
605
623
|
}
|
|
606
|
-
wrapped = @serialization_wrapping_renderer.serialize input, '*/*', self
|
|
624
|
+
wrapped = @serialization_wrapping_renderer.serialize input, '*/*', context: self
|
|
607
625
|
render body: wrapped
|
|
608
626
|
|
|
609
627
|
response.content_type = 'text/html'
|
|
@@ -44,35 +44,76 @@ module MediaTypes
|
|
|
44
44
|
validator = serializer_validator.view(view).version(v)
|
|
45
45
|
validator.override_suffix(:json) unless serializer_validated
|
|
46
46
|
|
|
47
|
-
serializer_output_registration.register_block(
|
|
47
|
+
serializer_output_registration.register_block(
|
|
48
|
+
self,
|
|
49
|
+
validator,
|
|
50
|
+
v,
|
|
51
|
+
block,
|
|
52
|
+
false,
|
|
53
|
+
wildcards:
|
|
54
|
+
!serializer_disable_wildcards
|
|
55
|
+
)
|
|
48
56
|
end
|
|
49
57
|
end
|
|
50
58
|
|
|
51
|
-
def output_raw(view: nil, version: nil, versions: nil, &block)
|
|
59
|
+
def output_raw(view: nil, version: nil, versions: nil, suffix: nil, &block)
|
|
52
60
|
versions = [version] if versions.nil?
|
|
53
61
|
raise VersionsNotAnArrayError unless versions.is_a? Array
|
|
54
62
|
|
|
55
63
|
raise ValidatorNotSpecifiedError, :output if serializer_validator.nil?
|
|
56
64
|
|
|
57
65
|
versions.each do |v|
|
|
58
|
-
validator = serializer_validator.view(view)
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
validator = serializer_validator.view(view)
|
|
67
|
+
.version(v)
|
|
68
|
+
.override_suffix(suffix)
|
|
69
|
+
|
|
70
|
+
serializer_output_registration.register_block(
|
|
71
|
+
self,
|
|
72
|
+
validator,
|
|
73
|
+
v,
|
|
74
|
+
block,
|
|
75
|
+
true,
|
|
76
|
+
wildcards: !serializer_disable_wildcards
|
|
77
|
+
)
|
|
61
78
|
end
|
|
62
79
|
end
|
|
63
80
|
|
|
64
|
-
def output_alias(
|
|
65
|
-
|
|
81
|
+
def output_alias(
|
|
82
|
+
media_type_identifier,
|
|
83
|
+
view: nil,
|
|
84
|
+
suffix: media_type_identifier == 'application/json' || media_type_identifier.end_with?('+json') ? :json : nil,
|
|
85
|
+
hide_variant: false
|
|
86
|
+
)
|
|
87
|
+
validator = serializer_validator.view(view).override_suffix(suffix)
|
|
66
88
|
victim_identifier = validator.identifier
|
|
67
89
|
|
|
68
|
-
serializer_output_registration.register_alias(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
90
|
+
serializer_output_registration.register_alias(
|
|
91
|
+
self,
|
|
92
|
+
media_type_identifier,
|
|
93
|
+
victim_identifier,
|
|
94
|
+
false,
|
|
95
|
+
hide_variant,
|
|
96
|
+
wildcards: !serializer_disable_wildcards
|
|
97
|
+
)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def output_alias_optional(
|
|
101
|
+
media_type_identifier,
|
|
102
|
+
view: nil,
|
|
103
|
+
suffix: media_type_identifier == 'application/json' || media_type_identifier.end_with?('+json') ? :json : nil,
|
|
104
|
+
hide_variant: false
|
|
105
|
+
)
|
|
106
|
+
validator = serializer_validator.view(view).override_suffix(suffix)
|
|
73
107
|
victim_identifier = validator.identifier
|
|
74
108
|
|
|
75
|
-
serializer_output_registration.register_alias(
|
|
109
|
+
serializer_output_registration.register_alias(
|
|
110
|
+
self,
|
|
111
|
+
media_type_identifier,
|
|
112
|
+
victim_identifier,
|
|
113
|
+
true,
|
|
114
|
+
hide_variant,
|
|
115
|
+
wildcards: !serializer_disable_wildcards
|
|
116
|
+
)
|
|
76
117
|
end
|
|
77
118
|
|
|
78
119
|
def input(view: nil, version: nil, versions: nil, &block)
|
|
@@ -89,39 +130,61 @@ module MediaTypes
|
|
|
89
130
|
end
|
|
90
131
|
end
|
|
91
132
|
|
|
92
|
-
def input_raw(view: nil, version: nil, versions: nil, &block)
|
|
133
|
+
def input_raw(view: nil, version: nil, versions: nil, suffix: nil, &block)
|
|
93
134
|
versions = [version] if versions.nil?
|
|
94
135
|
raise VersionsNotAnArrayError unless versions.is_a? Array
|
|
95
136
|
|
|
96
137
|
raise ValidatorNotSpecifiedError, :input if serializer_validator.nil?
|
|
97
138
|
|
|
98
139
|
versions.each do |v|
|
|
99
|
-
validator = serializer_validator.view(view).version(v)
|
|
140
|
+
validator = serializer_validator.view(view).version(v).override_suffix(suffix)
|
|
100
141
|
|
|
101
142
|
serializer_input_registration.register_block(self, validator, v, block, true)
|
|
102
143
|
end
|
|
103
144
|
end
|
|
104
145
|
|
|
105
|
-
def input_alias(
|
|
106
|
-
|
|
146
|
+
def input_alias(
|
|
147
|
+
media_type_identifier,
|
|
148
|
+
view: nil,
|
|
149
|
+
suffix: media_type_identifier == 'application/json' || media_type_identifier.end_with?('+json') ? :json : nil
|
|
150
|
+
)
|
|
151
|
+
validator = serializer_validator.view(view).override_suffix(suffix)
|
|
107
152
|
victim_identifier = validator.identifier
|
|
108
153
|
|
|
109
|
-
serializer_input_registration.register_alias(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
154
|
+
serializer_input_registration.register_alias(
|
|
155
|
+
self,
|
|
156
|
+
media_type_identifier,
|
|
157
|
+
victim_identifier,
|
|
158
|
+
false,
|
|
159
|
+
true,
|
|
160
|
+
wildcards: false
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def input_alias_optional(
|
|
165
|
+
media_type_identifier,
|
|
166
|
+
view: nil,
|
|
167
|
+
suffix: media_type_identifier == 'application/json' || media_type_identifier.end_with?('+json') ? :json : nil
|
|
168
|
+
)
|
|
169
|
+
validator = serializer_validator.view(view).override_suffix(suffix)
|
|
114
170
|
victim_identifier = validator.identifier
|
|
115
171
|
|
|
116
|
-
serializer_input_registration.register_alias(
|
|
172
|
+
serializer_input_registration.register_alias(
|
|
173
|
+
self,
|
|
174
|
+
media_type_identifier,
|
|
175
|
+
victim_identifier,
|
|
176
|
+
true,
|
|
177
|
+
true,
|
|
178
|
+
wildcards: false
|
|
179
|
+
)
|
|
117
180
|
end
|
|
118
181
|
|
|
119
|
-
def serialize(victim, media_type_identifier, context
|
|
182
|
+
def serialize(victim, media_type_identifier, context:, dsl: nil, raw: nil)
|
|
120
183
|
dsl ||= SerializationDSL.new(self, context: context)
|
|
121
184
|
serializer_output_registration.call(victim, media_type_identifier.to_s, context, dsl: dsl, raw: raw)
|
|
122
185
|
end
|
|
123
186
|
|
|
124
|
-
def deserialize(victim, media_type_identifier, context)
|
|
187
|
+
def deserialize(victim, media_type_identifier, context:)
|
|
125
188
|
serializer_input_registration.call(victim, media_type_identifier, context)
|
|
126
189
|
end
|
|
127
190
|
|
|
@@ -135,6 +198,8 @@ module MediaTypes
|
|
|
135
198
|
end
|
|
136
199
|
|
|
137
200
|
def self.inherited(subclass)
|
|
201
|
+
super
|
|
202
|
+
|
|
138
203
|
subclass.extend(ClassMethods)
|
|
139
204
|
subclass.instance_eval do
|
|
140
205
|
class << self
|
|
@@ -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)
|
|
@@ -36,7 +36,7 @@ module MediaTypes
|
|
|
36
36
|
|
|
37
37
|
unless registrations.key? target_identifier
|
|
38
38
|
potential_match = registrations.keys.find do |k|
|
|
39
|
-
k.
|
|
39
|
+
k.start_with? target_identifier
|
|
40
40
|
end
|
|
41
41
|
raise VersionedAliasDefinitionError.new(target_identifier, inout, potential_match) unless potential_match.nil?
|
|
42
42
|
raise UnbackedAliasDefinitionError.new(target_identifier, inout)
|
|
@@ -152,7 +152,7 @@ module MediaTypes
|
|
|
152
152
|
self.raw = raw
|
|
153
153
|
super(serializer, inout, validator, display_identifier)
|
|
154
154
|
end
|
|
155
|
-
|
|
155
|
+
|
|
156
156
|
def merge(other)
|
|
157
157
|
return nil unless other.is_a?(SerializationAliasRegistration)
|
|
158
158
|
|
|
@@ -37,7 +37,7 @@ Gem::Specification.new do |spec|
|
|
|
37
37
|
|
|
38
38
|
spec.add_dependency 'actionpack', '>= 4.0.0'
|
|
39
39
|
spec.add_dependency 'activesupport', '>= 4.0.0'
|
|
40
|
-
spec.add_dependency 'media_types', '>= 2.
|
|
40
|
+
spec.add_dependency 'media_types', '>= 2.1.0', '< 3.0.0'
|
|
41
41
|
|
|
42
42
|
spec.add_development_dependency 'awesome_print'
|
|
43
43
|
spec.add_development_dependency 'bundler'
|
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.4
|
|
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-12 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: actionpack
|
|
@@ -45,7 +45,7 @@ dependencies:
|
|
|
45
45
|
requirements:
|
|
46
46
|
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: 2.
|
|
48
|
+
version: 2.1.0
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
51
|
version: 3.0.0
|
|
@@ -55,7 +55,7 @@ dependencies:
|
|
|
55
55
|
requirements:
|
|
56
56
|
- - ">="
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: 2.
|
|
58
|
+
version: 2.1.0
|
|
59
59
|
- - "<"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
61
|
version: 3.0.0
|