media_types-serialization 1.0.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +7 -3
- data/.prettierrc +1 -0
- data/CHANGELOG.md +34 -8
- data/CODE_OF_CONDUCT.md +11 -11
- data/Gemfile.lock +137 -143
- data/README.md +182 -91
- data/lib/media_types/serialization.rb +94 -20
- data/lib/media_types/serialization/base.rb +12 -8
- data/lib/media_types/serialization/error.rb +11 -3
- data/lib/media_types/serialization/fake_validator.rb +1 -1
- data/lib/media_types/serialization/serialization_dsl.rb +3 -3
- data/lib/media_types/serialization/serialization_registration.rb +19 -9
- data/lib/media_types/serialization/serializers/problem_serializer.rb +23 -10
- data/lib/media_types/serialization/utils/accept_header.rb +77 -0
- data/lib/media_types/serialization/utils/accept_language_header.rb +82 -0
- data/lib/media_types/serialization/utils/header_list.rb +89 -0
- data/lib/media_types/serialization/version.rb +1 -1
- data/media_types-serialization.gemspec +1 -3
- metadata +12 -42
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/.github/workflows/ci.yml
CHANGED
@@ -5,7 +5,7 @@ on:
|
|
5
5
|
branches:
|
6
6
|
- master
|
7
7
|
push:
|
8
|
-
branches:
|
8
|
+
branches:
|
9
9
|
- master
|
10
10
|
- depfu/*
|
11
11
|
- release/*
|
@@ -16,12 +16,16 @@ jobs:
|
|
16
16
|
|
17
17
|
runs-on: ubuntu-latest
|
18
18
|
|
19
|
+
strategy:
|
20
|
+
matrix:
|
21
|
+
ruby-version: [2.7.x, 2.6.x]
|
22
|
+
|
19
23
|
steps:
|
20
24
|
- uses: actions/checkout@v1
|
21
|
-
- name: Set up Ruby
|
25
|
+
- name: Set up Ruby ${{ matrix.ruby-version }}
|
22
26
|
uses: actions/setup-ruby@v1
|
23
27
|
with:
|
24
|
-
ruby-version:
|
28
|
+
ruby-version: ${{ matrix.ruby-version }}
|
25
29
|
- name: Build and test with Rake
|
26
30
|
run: |
|
27
31
|
gem install bundler
|
data/.prettierrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{}
|
data/CHANGELOG.md
CHANGED
@@ -1,23 +1,49 @@
|
|
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
|
+
|
9
|
+
## 1.2.0
|
10
|
+
|
11
|
+
- ✨ Add `view:` to `output_html` which renders a specific rails view.
|
12
|
+
|
13
|
+
## 1.1.0
|
14
|
+
|
15
|
+
- ✨ Add _allow_output_html_: Fallback to rails rendering.
|
16
|
+
- ✨ Add _allow_output_docs_: Useful to add a documentation description to endpoints that you can normally only POST to.
|
17
|
+
- ✨ Add _output_error_: Implements missing content-language support.
|
18
|
+
- ✨ Add _scoped freeze_io! support_: Useful for gradual adoption of mediatypes on existing routes.
|
19
|
+
- ✨ Add _alias variant reporting_: Allows reporting what the original matched media type was even when impersonating a different media type.
|
20
|
+
- ✨ Improve README: small improvements to make it easier to adopt and upgrade existing codebase.
|
21
|
+
- ✨ Reduce number of (external) dependencies
|
22
|
+
- 🐛 Fix incorrect output on encoding errors.
|
23
|
+
- 🐛 Fix message in various alias error messages.
|
24
|
+
|
25
|
+
## 1.0.3
|
26
|
+
|
27
|
+
- 🐛 Unvalidated serializers would put the view part of the identifier before the version. This was not in line with validated serializers.
|
28
|
+
|
3
29
|
## 1.0.2
|
4
30
|
|
5
|
-
|
31
|
+
- 🐛 Explicitly set all oj parameters when decoding as well.
|
6
32
|
|
7
33
|
## 1.0.1
|
8
34
|
|
9
|
-
|
10
|
-
|
35
|
+
- 🐛 Explicitly set all oj and json parameters to ensure correct behavior with changed defaults.
|
36
|
+
- 🐛 Fix serializer not deserializing as symbols.
|
11
37
|
|
12
38
|
## 1.0.0
|
13
39
|
|
14
40
|
- ✨ Add support for input deserialization.
|
15
|
-
- ✨
|
16
|
-
- ✨
|
17
|
-
- ✨
|
18
|
-
- ✨
|
41
|
+
- ✨ Add serializer DSL to be more in line with validation gem.
|
42
|
+
- ✨ Add ability to make a serializer without a validator.
|
43
|
+
- ✨ Add error serializer that emits [`application/problem+json`](https://tools.ietf.org/html/rfc7231).
|
44
|
+
- ✨ Reduce number of dependencies.
|
19
45
|
- ✨ Validators no longer need to be registered to be used.
|
20
|
-
- ✨
|
46
|
+
- ✨ Add a [wiki where errors can be documented](https://docs.delftsolutions.nl). Feel free to make pages for your own namespaced errors.
|
21
47
|
- 💔 Serializer definition API has backwards incompatible changes.
|
22
48
|
- 💔 API viewer is now no longer registered as html but accessible with the `?api_viewer=last` query parameter.
|
23
49
|
- 💔 Validators can no longer be registered for use in `format do`.
|
data/CODE_OF_CONDUCT.md
CHANGED
@@ -14,21 +14,21 @@ orientation.
|
|
14
14
|
Examples of behavior that contributes to creating a positive environment
|
15
15
|
include:
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
- Using welcoming and inclusive language
|
18
|
+
- Being respectful of differing viewpoints and experiences
|
19
|
+
- Gracefully accepting constructive criticism
|
20
|
+
- Focusing on what is best for the community
|
21
|
+
- Showing empathy towards other community members
|
22
22
|
|
23
23
|
Examples of unacceptable behavior by participants include:
|
24
24
|
|
25
|
-
|
26
|
-
advances
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
- The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
- Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
- Public or private harassment
|
29
|
+
- Publishing others' private information, such as a physical or electronic
|
30
30
|
address, without explicit permission
|
31
|
-
|
31
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
32
32
|
professional setting
|
33
33
|
|
34
34
|
## Our Responsibilities
|
data/Gemfile.lock
CHANGED
@@ -1,143 +1,137 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
media_types-serialization (1.0
|
5
|
-
actionpack (>= 4.0.0)
|
6
|
-
activesupport (>= 4.0.0)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
oj
|
139
|
-
rails (~> 5.2)
|
140
|
-
rake (~> 13.0)
|
141
|
-
|
142
|
-
BUNDLED WITH
|
143
|
-
1.17.3
|
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
@@ -4,7 +4,7 @@
|
|
4
4
|
[](https://badge.fury.io/rb/media_types-serialization)
|
5
5
|
[](http://opensource.org/licenses/MIT)
|
6
6
|
|
7
|
-
`respond_to` on steroids. Add
|
7
|
+
`respond_to` on steroids. Add [HATEOAS](https://docs.delftsolutions.nl/wiki/HATEOAS_API) compatible serialization and deserialization to your Rails projects.
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
@@ -57,9 +57,67 @@ BookSerializer.serialize(book, 'vnd.acme.book.v1+json', context: nil)
|
|
57
57
|
# => { "book": { "title": "Everything, abridged" } }
|
58
58
|
```
|
59
59
|
|
60
|
+
### Controller integration
|
61
|
+
|
62
|
+
You can integrate the serialization system in rails, giving you automatic [Content-Type negotiation](https://en.wikipedia.org/wiki/Content_negotiation) using the `Accept` header:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
require 'media_types/serialization'
|
66
|
+
|
67
|
+
class BookController < ActionController::API
|
68
|
+
include MediaTypes::Serialization
|
69
|
+
|
70
|
+
allow_output_serializer(BookSerializer, only: %i[show])
|
71
|
+
freeze_io!
|
72
|
+
|
73
|
+
def show
|
74
|
+
book = Book.new
|
75
|
+
book.title = 'Everything, abridged'
|
76
|
+
|
77
|
+
render_media book
|
78
|
+
end
|
79
|
+
end
|
80
|
+
```
|
81
|
+
|
82
|
+
While using the controller integration the context will always be set to the current controller.
|
83
|
+
This allows you to construct urls.
|
84
|
+
|
85
|
+
### Adding HATEOAS responses to existing routes
|
86
|
+
|
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:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
class BookController < ApplicationController
|
92
|
+
def show
|
93
|
+
@book = Book.new
|
94
|
+
|
95
|
+
# Use view corresponding to the controller
|
96
|
+
end
|
97
|
+
end
|
98
|
+
```
|
99
|
+
|
100
|
+
You can add a json representation as follows:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
class BookController < ApplicationController
|
104
|
+
allow_output_serializer(BookSerializer, only: %i[show])
|
105
|
+
allow_output_html
|
106
|
+
freeze_io!
|
107
|
+
|
108
|
+
def show
|
109
|
+
@book = Book.new
|
110
|
+
|
111
|
+
render_media @book
|
112
|
+
end
|
113
|
+
end
|
114
|
+
```
|
115
|
+
|
60
116
|
### Validations
|
61
117
|
|
62
|
-
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):
|
63
121
|
|
64
122
|
```ruby
|
65
123
|
require 'media_types'
|
@@ -98,30 +156,6 @@ end
|
|
98
156
|
|
99
157
|
For more information, see the [Media Types docs](https://github.com/SleeplessByte/media-types-ruby).
|
100
158
|
|
101
|
-
### Controller integration
|
102
|
-
|
103
|
-
You can integrate the serialization system in rails, giving you automatic [Content-Type negotiation](https://en.wikipedia.org/wiki/Content_negotiation) using the `Accept` header:
|
104
|
-
|
105
|
-
```ruby
|
106
|
-
require 'media_types/serialization'
|
107
|
-
|
108
|
-
class BookController < ActionController::API
|
109
|
-
include MediaTypes::Serialization
|
110
|
-
|
111
|
-
allow_output_serializer(BookSerializer, only: %i[show])
|
112
|
-
freeze_io!
|
113
|
-
|
114
|
-
def show
|
115
|
-
book = Book.new
|
116
|
-
book.title = 'Everything, abridged'
|
117
|
-
|
118
|
-
render_media book
|
119
|
-
end
|
120
|
-
end
|
121
|
-
```
|
122
|
-
|
123
|
-
While using the controller integration the context will always be set to the current controller. This allows you to construct urls.
|
124
|
-
|
125
159
|
### Versioning
|
126
160
|
|
127
161
|
To help with supporting older versions, serializers have a [DSL](https://en.wikipedia.org/wiki/Domain-specific_language) to construct json objects:
|
@@ -149,7 +183,8 @@ BookSerializer.serialize(book, BookValidator.version(2), context: nil)
|
|
149
183
|
|
150
184
|
### Links
|
151
185
|
|
152
|
-
When making [HATEOAS](https://
|
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:
|
153
188
|
|
154
189
|
```ruby
|
155
190
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -188,7 +223,8 @@ There are convenience methods for serializing arrays of objects based on a templ
|
|
188
223
|
|
189
224
|
#### Indexes
|
190
225
|
|
191
|
-
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.
|
192
228
|
|
193
229
|
```ruby
|
194
230
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -206,7 +242,7 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
206
242
|
output view: :index, version: 3 do |arr, version, context|
|
207
243
|
attribute :books do
|
208
244
|
link :self, href: context.book_index_url
|
209
|
-
|
245
|
+
|
210
246
|
index arr, version: version
|
211
247
|
end
|
212
248
|
end
|
@@ -230,7 +266,8 @@ BookSerializer.serialize([book], BookValidator.view(:index).version(3), context:
|
|
230
266
|
|
231
267
|
#### Collections
|
232
268
|
|
233
|
-
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.
|
234
271
|
|
235
272
|
```ruby
|
236
273
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -248,15 +285,15 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
248
285
|
output view: :index, version: 3 do |arr, version, context|
|
249
286
|
attribute :books do
|
250
287
|
link :self, href: context.book_index_url
|
251
|
-
|
288
|
+
|
252
289
|
index arr, version: version
|
253
290
|
end
|
254
291
|
end
|
255
|
-
|
292
|
+
|
256
293
|
output view: :collection, version: 3 do |arr, version, context|
|
257
294
|
attribute :books do
|
258
295
|
link :self, href: context.book_collection_url
|
259
|
-
|
296
|
+
|
260
297
|
collection arr, version: version
|
261
298
|
end
|
262
299
|
end
|
@@ -299,6 +336,7 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
299
336
|
attribute :title, obj.title
|
300
337
|
attribute :description, obj.description if version >= 2
|
301
338
|
end
|
339
|
+
end
|
302
340
|
|
303
341
|
input version: 3
|
304
342
|
end
|
@@ -309,16 +347,16 @@ class BookController < ActionController::API
|
|
309
347
|
allow_output_serializer(BookSerializer, only: %i[show])
|
310
348
|
allow_input_serializer(BookSerializer, only: %i[create])
|
311
349
|
freeze_io!
|
312
|
-
|
313
|
-
def show
|
350
|
+
|
351
|
+
def show
|
314
352
|
book = Book.new
|
315
353
|
book.title = 'Everything, abridged'
|
316
354
|
|
317
|
-
|
355
|
+
render_media serialize_media(book)
|
318
356
|
end
|
319
357
|
|
320
358
|
def create
|
321
|
-
json = deserialize(request
|
359
|
+
json = deserialize(request) # does validation for us
|
322
360
|
puts json
|
323
361
|
end
|
324
362
|
end
|
@@ -355,19 +393,19 @@ class BookController < ActionController::API
|
|
355
393
|
allow_output_serializer(BookSerializer, only: %i[show])
|
356
394
|
allow_input_serializer(BookSerializer, only: %i[create])
|
357
395
|
freeze_io!
|
358
|
-
|
359
|
-
def show
|
396
|
+
|
397
|
+
def show
|
360
398
|
book = Book.new
|
361
399
|
book.title = 'Everything, abridged'
|
362
400
|
|
363
|
-
|
401
|
+
render_media serialize_media(book)
|
364
402
|
end
|
365
403
|
|
366
404
|
def create
|
367
|
-
book = deserialize(request
|
405
|
+
book = deserialize(request)
|
368
406
|
book.save!
|
369
407
|
|
370
|
-
|
408
|
+
render_media serialize_media(book)
|
371
409
|
end
|
372
410
|
end
|
373
411
|
```
|
@@ -376,7 +414,9 @@ If you don't want to apply any input validation or deserialization you can use t
|
|
376
414
|
|
377
415
|
### Raw output
|
378
416
|
|
379
|
-
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:
|
380
420
|
|
381
421
|
```ruby
|
382
422
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -385,7 +425,7 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
385
425
|
output_raw view: :raw, version: 3 do |obj, version, context|
|
386
426
|
hidden do
|
387
427
|
# Make sure links are only set in the headers, not in the body.
|
388
|
-
|
428
|
+
|
389
429
|
link :self, href: context.book_url(obj)
|
390
430
|
end
|
391
431
|
|
@@ -413,7 +453,8 @@ end
|
|
413
453
|
|
414
454
|
### Remapping media type identifiers
|
415
455
|
|
416
|
-
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:
|
417
458
|
|
418
459
|
```ruby
|
419
460
|
class BookSerializer < MediaTypes::Serialization::Base
|
@@ -445,7 +486,8 @@ Validation will be done using the remapped validator. Aliasses map to version `n
|
|
445
486
|
|
446
487
|
### HTML
|
447
488
|
|
448
|
-
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.
|
449
491
|
|
450
492
|
To enable the API viewer, use: `allow_api_viewer` in the controller.
|
451
493
|
|
@@ -454,22 +496,20 @@ class BookController < ActionController::API
|
|
454
496
|
include MediaTypes::Serialization
|
455
497
|
|
456
498
|
allow_api_viewer
|
457
|
-
|
458
|
-
allow_output_serializer(MediaTypes::ApiViewer)
|
459
499
|
|
460
500
|
allow_output_serializer(BookSerializer, only: %i[show])
|
461
501
|
allow_input_serializer(BookSerializer, only: %i[create])
|
462
502
|
freeze_io!
|
463
|
-
|
464
|
-
def show
|
503
|
+
|
504
|
+
def show
|
465
505
|
book = Book.new
|
466
506
|
book.title = 'Everything, abridged'
|
467
507
|
|
468
|
-
|
508
|
+
render_media serialize_media(book)
|
469
509
|
end
|
470
510
|
|
471
511
|
def create
|
472
|
-
json = deserialize(request
|
512
|
+
json = deserialize(request) # does validation for us
|
473
513
|
puts json
|
474
514
|
end
|
475
515
|
end
|
@@ -489,45 +529,48 @@ class BookSerializer < MediaTypes::Serialization::Base
|
|
489
529
|
attribute :description, obj.description if version >= 2
|
490
530
|
end
|
491
531
|
end
|
492
|
-
|
532
|
+
|
493
533
|
output_raw view: :html do |obj, context|
|
494
534
|
render_view 'book/show', context: context, assigns: {
|
495
535
|
title: obj.title,
|
496
536
|
description: obj.description
|
497
537
|
}
|
498
538
|
end
|
499
|
-
|
539
|
+
|
500
540
|
output_alias 'text/html', view: :html
|
501
541
|
end
|
502
542
|
```
|
503
543
|
|
504
544
|
#### Errors
|
505
545
|
|
506
|
-
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!`:
|
507
548
|
|
508
549
|
```ruby
|
509
550
|
class BookController < ActionController::API
|
510
551
|
include MediaTypes::Serialization
|
511
552
|
|
512
|
-
output_error CanCan::AccessDenied do |
|
513
|
-
|
514
|
-
|
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'
|
515
556
|
|
516
|
-
|
557
|
+
problem_output.status_code :forbidden
|
517
558
|
end
|
518
559
|
|
519
560
|
freeze_io!
|
520
561
|
|
521
|
-
# ...
|
562
|
+
# ...
|
522
563
|
end
|
523
564
|
```
|
524
565
|
|
525
|
-
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.
|
526
|
-
|
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.
|
527
569
|
|
528
|
-
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.
|
529
572
|
|
530
|
-
Custom attributes can be added using the `
|
573
|
+
Custom attributes can be added using the `problem_output.attribute(name, value)` function.
|
531
574
|
|
532
575
|
### Related
|
533
576
|
|
@@ -553,31 +596,47 @@ Either validator or unvalidated must be used while defining a serializer.
|
|
553
596
|
|
554
597
|
#### `output( view:, version:, versions: ) do |obj, version, context|`
|
555
598
|
|
556
|
-
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.
|
557
601
|
|
558
|
-
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.
|
559
604
|
|
560
605
|
The block should return an object to convert into JSON.
|
561
606
|
|
562
607
|
#### `output_raw( view:, version:, versions: ) do |obj, version, context|`
|
563
608
|
|
564
|
-
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.
|
611
|
+
|
612
|
+
#### `output_alias( media_type_identifier, view:, hide_variant: false )`
|
613
|
+
|
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.
|
565
616
|
|
566
|
-
|
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]`.
|
567
619
|
|
568
|
-
|
620
|
+
> You cannot alias a _versioned_ media type, otherwise it would be easy to later break the definition by changing the version it aliases.
|
569
621
|
|
570
|
-
#### `output_alias_optional( media_type_identifier, view: )`
|
622
|
+
#### `output_alias_optional( media_type_identifier, view:, hide_variant: false )`
|
571
623
|
|
572
|
-
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.
|
627
|
+
|
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]`.
|
573
629
|
|
574
630
|
#### `input( view:, version:, versions: ) do |obj, version, context|`
|
575
631
|
|
576
|
-
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.
|
577
634
|
|
578
|
-
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.
|
579
637
|
|
580
|
-
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.
|
581
640
|
|
582
641
|
#### `input_raw( view:, version:, versions: ) do |bytes, version, context|`
|
583
642
|
|
@@ -585,11 +644,17 @@ This has the same behavior as `input` but takes in raw data. Input is not valida
|
|
585
644
|
|
586
645
|
#### `input_alias( media_type_identifier, view: )`
|
587
646
|
|
588
|
-
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.
|
589
652
|
|
590
653
|
#### `input_alias_optional( media_type_identifier, view: )`
|
591
654
|
|
592
|
-
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.
|
593
658
|
|
594
659
|
#### `disable_wildcards`
|
595
660
|
|
@@ -601,13 +666,15 @@ The following methods are available within an `output ... do` block.
|
|
601
666
|
|
602
667
|
#### `attribute( key, value = {} ) do`
|
603
668
|
|
604
|
-
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`.
|
605
671
|
|
606
672
|
Returns the built up context so far.
|
607
673
|
|
608
674
|
#### `link( rel, href:, emit_header: true, **attributes )`
|
609
675
|
|
610
|
-
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.
|
611
678
|
|
612
679
|
If `emit_header` is `true` the link will also be emitted as a http header.
|
613
680
|
|
@@ -628,7 +695,9 @@ Returns the built up context so far.
|
|
628
695
|
|
629
696
|
#### `hidden do`
|
630
697
|
|
631
|
-
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.
|
632
701
|
|
633
702
|
Returns the unmodified context.
|
634
703
|
|
@@ -652,13 +721,31 @@ These functions are available during the controller definition if you add `inclu
|
|
652
721
|
|
653
722
|
#### `allow_output_serializer( serializer, views: nil, **filters )`
|
654
723
|
|
655
|
-
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.
|
726
|
+
|
727
|
+
Accepts the same filters as `before_action`.
|
728
|
+
|
729
|
+
#### `allow_output_html( as: nil, view: nil, layout: nil, **filters )`
|
730
|
+
|
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.
|
732
|
+
|
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`.
|
735
|
+
|
736
|
+
Accepts the same filters as `before_action`.
|
737
|
+
You can set the template to use using the `view:` parameter.
|
738
|
+
|
739
|
+
#### `allow_output_docs( description, **filters )`
|
740
|
+
|
741
|
+
Outputs the specified description as help information.
|
656
742
|
|
657
743
|
Accepts the same filters as `before_action`.
|
658
744
|
|
659
745
|
#### `allow_input_serializer( serializer, views: nil, **filters )`
|
660
746
|
|
661
|
-
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.
|
662
749
|
|
663
750
|
Accepts the same filters as `before_action`.
|
664
751
|
|
@@ -690,9 +777,10 @@ Clears the list of serializers used to render the error when the client supplies
|
|
690
777
|
|
691
778
|
Enables rendering the api viewer when adding the `api_viewer=last` query parameter to the url.
|
692
779
|
|
693
|
-
#### `freeze_io
|
780
|
+
#### `freeze_io!(**filter_opts)`
|
694
781
|
|
695
|
-
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.
|
696
784
|
|
697
785
|
### Controller usage
|
698
786
|
|
@@ -700,7 +788,8 @@ These functions are available during method execution in the controller.
|
|
700
788
|
|
701
789
|
#### `render_media( obj, serializers: nil, not_acceptable_serializer: nil, **options ) do`
|
702
790
|
|
703
|
-
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:
|
704
793
|
|
705
794
|
```ruby
|
706
795
|
render_media do
|
@@ -711,13 +800,15 @@ render_media do
|
|
711
800
|
end
|
712
801
|
```
|
713
802
|
|
714
|
-
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.
|
715
805
|
|
716
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.
|
717
807
|
|
718
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.
|
719
809
|
|
720
|
-
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.
|
721
812
|
|
722
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.
|
723
814
|
|
@@ -740,6 +831,7 @@ Does the same as `deserialize( request )` but gives the client an error page if
|
|
740
831
|
Returns the serializer class that will handle the given request.
|
741
832
|
|
742
833
|
## Customization
|
834
|
+
|
743
835
|
The easiest way to customize the look and feel of the built in pages is to provide your own logo and background in an initializer:
|
744
836
|
|
745
837
|
```ruby
|
@@ -758,12 +850,11 @@ HERE
|
|
758
850
|
|
759
851
|
## Development
|
760
852
|
|
761
|
-
After checking out the repo, run `bin/setup` to install dependencies.
|
762
|
-
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.
|
763
855
|
|
764
|
-
To install this gem onto your local machine, run `bundle exec rake install`.
|
765
|
-
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
766
|
-
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).
|
767
858
|
|
768
859
|
## Contributing
|
769
860
|
|