media_types-serialization 1.0.2 → 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/.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
|
[![Gem Version](https://badge.fury.io/rb/media_types-serialization.svg)](https://badge.fury.io/rb/media_types-serialization)
|
5
5
|
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](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
|
|