media_types 0.6.2 → 2.1.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/debian.yml +42 -0
- data/.github/workflows/ruby.yml +22 -0
- data/.gitignore +10 -10
- data/CHANGELOG.md +76 -41
- data/Gemfile +6 -6
- data/Gemfile.lock +17 -83
- data/LICENSE +21 -0
- data/README.md +364 -91
- data/Rakefile +12 -12
- data/lib/media_types.rb +58 -2
- data/lib/media_types/constructable.rb +36 -10
- data/lib/media_types/dsl.rb +110 -29
- data/lib/media_types/dsl/errors.rb +18 -0
- data/lib/media_types/errors.rb +19 -0
- data/lib/media_types/scheme.rb +153 -2
- data/lib/media_types/scheme/errors.rb +66 -0
- data/lib/media_types/scheme/links.rb +15 -0
- data/lib/media_types/scheme/missing_validation.rb +12 -4
- data/lib/media_types/scheme/output_empty_guard.rb +5 -4
- data/lib/media_types/scheme/output_iterator_with_predicate.rb +13 -2
- data/lib/media_types/scheme/output_type_guard.rb +1 -1
- data/lib/media_types/scheme/rules.rb +53 -1
- data/lib/media_types/scheme/rules_exhausted_guard.rb +15 -4
- data/lib/media_types/scheme/validation_options.rb +17 -5
- data/lib/media_types/testing/assertions.rb +20 -0
- data/lib/media_types/validations.rb +15 -5
- data/lib/media_types/version.rb +1 -1
- data/media_types.gemspec +4 -7
- metadata +20 -62
- data/.travis.yml +0 -19
- data/lib/media_types/defaults.rb +0 -31
- data/lib/media_types/integrations.rb +0 -32
- data/lib/media_types/integrations/actionpack.rb +0 -21
- data/lib/media_types/integrations/http.rb +0 -47
- data/lib/media_types/minitest/assert_media_type_format.rb +0 -10
- data/lib/media_types/minitest/assert_media_types_registered.rb +0 -166
- data/lib/media_types/registrar.rb +0 -148
data/README.md
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
# MediaTypes
|
2
|
-
[![Build Status](https://
|
2
|
+
[![Build Status](https://github.com/SleeplessByte/media-types-ruby/workflows/Ruby/badge.svg?branch=master)](https://github.com/SleeplessByte/media-types-ruby/actions?query=workflow%3ARuby)
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/media_types.svg)](https://badge.fury.io/rb/media_types)
|
4
4
|
[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
|
5
5
|
[![Maintainability](https://api.codeclimate.com/v1/badges/6f2dc1fb37ecb98c4363/maintainability)](https://codeclimate.com/github/SleeplessByte/media-types-ruby/maintainability)
|
6
6
|
|
7
|
-
Media Types based on scheme, with versioning, views, suffixes and validations.
|
7
|
+
Media Types based on scheme, with versioning, views, suffixes and validations.
|
8
|
+
|
9
|
+
This library makes it easy to define schemas that can be used to validate JSON objects based on their Content-Type.
|
8
10
|
|
9
11
|
## Installation
|
10
12
|
|
@@ -24,15 +26,33 @@ Or install it yourself as:
|
|
24
26
|
|
25
27
|
## Usage
|
26
28
|
|
27
|
-
|
29
|
+
Define a validation:
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
require 'media_types'
|
33
|
+
|
34
|
+
module Acme
|
35
|
+
MediaTypes::set_organisation Acme, 'acme'
|
36
|
+
|
37
|
+
class FooValidator
|
38
|
+
include MediaTypes::Dsl
|
28
39
|
|
29
|
-
|
30
|
-
|
40
|
+
use_name 'foo'
|
41
|
+
|
42
|
+
validations do
|
43
|
+
attribute :foo, String
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
```
|
31
48
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
49
|
+
Validate an object:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
Acme::FooValidator.validate!({ foo: 'bar' })
|
53
|
+
```
|
54
|
+
|
55
|
+
## Full example
|
36
56
|
|
37
57
|
```Ruby
|
38
58
|
require 'media_types'
|
@@ -40,22 +60,24 @@ require 'media_types'
|
|
40
60
|
class Venue
|
41
61
|
include MediaTypes::Dsl
|
42
62
|
|
43
|
-
def self.
|
44
|
-
'
|
63
|
+
def self.organisation
|
64
|
+
'mydomain'
|
45
65
|
end
|
46
66
|
|
47
|
-
|
67
|
+
use_name 'venue'
|
48
68
|
|
49
69
|
validations do
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
70
|
+
version 2 do
|
71
|
+
attribute :name, String
|
72
|
+
collection :location do
|
73
|
+
attribute :latitude, Numeric
|
74
|
+
attribute :longitude, Numeric
|
75
|
+
attribute :altitude, AllowNil(Numeric)
|
76
|
+
end
|
56
77
|
|
57
|
-
|
58
|
-
|
78
|
+
link :self
|
79
|
+
link :route, allow_nil: true
|
80
|
+
end
|
59
81
|
|
60
82
|
version 1 do
|
61
83
|
attribute :name, String
|
@@ -81,35 +103,24 @@ class Venue
|
|
81
103
|
end
|
82
104
|
end
|
83
105
|
end
|
84
|
-
|
85
|
-
registrations :venue_json do
|
86
|
-
view 'create', :create_venue
|
87
|
-
view 'index', :venue_urls
|
88
|
-
view 'collection', :venue_collection
|
89
|
-
|
90
|
-
versions [1,2]
|
91
|
-
|
92
|
-
suffix :json
|
93
|
-
suffix :xml
|
94
|
-
end
|
95
106
|
end
|
96
107
|
```
|
97
108
|
|
98
109
|
## Schema Definitions
|
99
110
|
|
100
|
-
If you
|
111
|
+
If you include 'MediaTypes::Dsl' in your class you can use the following functions within a `validation do` block to define your schema:
|
101
112
|
|
102
113
|
### `attribute`
|
103
114
|
|
104
115
|
Adds an attribute to the schema, if a +block+ is given, uses that to test against instead of +type+
|
105
116
|
|
106
|
-
| param
|
107
|
-
|
108
|
-
| key
|
109
|
-
| opts
|
110
|
-
| type
|
111
|
-
| optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false`
|
112
|
-
| &block
|
117
|
+
| param | type | description |
|
118
|
+
| --------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
119
|
+
| key | `Symbol` | the attribute name |
|
120
|
+
| opts | `Hash` | options to pass to `Scheme` or `Attribute` |
|
121
|
+
| type | `Class`, `===`, Scheme | The type of the value can be anything that responds to `===`, or scheme to use if no `&block` is given. Defaults to `Object` without a `&block` and to Hash with a `&block`. |
|
122
|
+
| optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
|
123
|
+
| &block | `Block` | defines the scheme of the value of this attribute |
|
113
124
|
|
114
125
|
#### Add an attribute named foo, expecting a string
|
115
126
|
```Ruby
|
@@ -147,12 +158,12 @@ MyMedia.valid?({ foo: { bar: 'my-string' }})
|
|
147
158
|
### `any`
|
148
159
|
Allow for any key. The `&block` defines the Schema for each value.
|
149
160
|
|
150
|
-
| param
|
151
|
-
|
152
|
-
| scheme
|
153
|
-
| allow_empty:
|
154
|
-
| expected_type: | `Class`,
|
155
|
-
| &block
|
161
|
+
| param | type | description |
|
162
|
+
| -------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------ |
|
163
|
+
| scheme | `Scheme`, `NilClass` | scheme to use if no `&block` is given |
|
164
|
+
| allow_empty: | `TrueClass`, `FalsClass` | if true, empty (no key/value present) is allowed |
|
165
|
+
| expected_type: | `Class`, | forces the validated value to have this type, defaults to `Hash`. Use `Object` if either `Hash` or `Array` is fine |
|
166
|
+
| &block | `Block` | defines the scheme of the value of this attribute |
|
156
167
|
|
157
168
|
#### Add a collection named foo, expecting any key with a defined value
|
158
169
|
```Ruby
|
@@ -196,14 +207,14 @@ MyMedia.valid?({ foo: [{ required: 'test', bar: 42 }] })
|
|
196
207
|
### `collection`
|
197
208
|
Expect a collection such as an array or hash. The `&block` defines the Schema for each item in that collection.
|
198
209
|
|
199
|
-
| param
|
200
|
-
|
201
|
-
| key
|
202
|
-
| scheme
|
203
|
-
| allow_empty:
|
204
|
-
| expected_type: | `Class`,
|
205
|
-
| optional:
|
206
|
-
| &block
|
210
|
+
| param | type | description |
|
211
|
+
| -------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
212
|
+
| key | `Symbol` | key of the collection (same as `#attribute`) |
|
213
|
+
| scheme | `Scheme`, `NilClass`, `Class` | scheme to use if no `&block` is given or `Class` of each item in the collection |
|
214
|
+
| allow_empty: | `TrueClass`, `FalseClass` | if true, empty (no key/value present) is allowed |
|
215
|
+
| expected_type: | `Class`, | forces the validated value to have this type, defaults to `Array`. Use `Object` if either `Array` or `Hash` is fine. |
|
216
|
+
| optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
|
217
|
+
| &block | `Block` | defines the scheme of the value of this attribute |
|
207
218
|
|
208
219
|
|
209
220
|
#### Collection with an array of string
|
@@ -242,12 +253,12 @@ MyMedia.valid?({ foo: [{ required: 'test', number: 42 }, { required: 'other', nu
|
|
242
253
|
|
243
254
|
Expect a link with a required `href: String` attribute
|
244
255
|
|
245
|
-
| param
|
246
|
-
|
247
|
-
| key
|
248
|
-
| allow_nil: | `TrueClass`, `FalseClass` | if true, value may be nil
|
249
|
-
| optional:
|
250
|
-
| &block
|
256
|
+
| param | type | description |
|
257
|
+
| ---------- | ------------------------- | -------------------------------------------------------------------------------------- |
|
258
|
+
| key | `Symbol` | key of the link (same as `#attribute`) |
|
259
|
+
| allow_nil: | `TrueClass`, `FalseClass` | if true, value may be nil |
|
260
|
+
| optional: | `TrueClass`, `FalseClass` | if true, key may be absent, defaults to `false` |
|
261
|
+
| &block | `Block` | defines the scheme of the value of this attribute, in addition to the `href` attribute |
|
251
262
|
|
252
263
|
#### Links as defined in HAL, JSON-Links and other specs
|
253
264
|
```Ruby
|
@@ -255,7 +266,7 @@ class MyMedia
|
|
255
266
|
include MediaTypes::Dsl
|
256
267
|
|
257
268
|
validations do
|
258
|
-
link :
|
269
|
+
link :self
|
259
270
|
link :image
|
260
271
|
end
|
261
272
|
end
|
@@ -315,69 +326,331 @@ expected_object.valid?([{ foo: 'string' }])
|
|
315
326
|
```
|
316
327
|
|
317
328
|
## Formatting for headers
|
318
|
-
Any media type object can be
|
329
|
+
Any media type object can be converted in valid string to be used with `Content-Type` or `Accept`:
|
319
330
|
|
320
331
|
```Ruby
|
321
|
-
Venue.mime_type.
|
332
|
+
Venue.mime_type.identifier
|
322
333
|
# => "application/vnd.mydomain.venue.v2+json"
|
323
334
|
|
324
|
-
Venue.mime_type.version(1).
|
335
|
+
Venue.mime_type.version(1).identifier
|
325
336
|
# => "application/vnd.mydomain.venue.v1+json"
|
326
337
|
|
327
|
-
Venue.mime_type.version(1).suffix(:xml).to_s
|
328
|
-
# => "application/vnd.mydomain.venue.v1+xml"
|
329
|
-
|
330
338
|
Venue.mime_type.to_s(0.2)
|
331
339
|
# => "application/vnd.mydomain.venue.v2+json; q=0.2"
|
332
340
|
|
333
|
-
Venue.mime_type.collection.
|
341
|
+
Venue.mime_type.collection.identifier
|
334
342
|
# => "application/vnd.mydomain.venue.v2.collection+json"
|
335
343
|
|
336
|
-
Venue.mime_type.view('active').
|
344
|
+
Venue.mime_type.view('active').identifier
|
337
345
|
# => "application/vnd.mydomain.venue.v2.active+json"
|
338
346
|
```
|
339
347
|
|
340
|
-
##
|
341
|
-
|
348
|
+
## API
|
349
|
+
|
350
|
+
A defined schema has the following functions available:
|
351
|
+
|
352
|
+
### `valid?`
|
353
|
+
|
354
|
+
Example: `Venue.valid?({ foo: 'bar' })`
|
355
|
+
|
356
|
+
Allows passing in validation options as a second parameter.
|
357
|
+
|
358
|
+
### `validate!`
|
359
|
+
|
360
|
+
Example: `Venue.validate!({ foo: 'bar' })`
|
361
|
+
|
362
|
+
Allows passing in validation options as a second parameter.
|
363
|
+
|
364
|
+
### `validatable?`
|
365
|
+
|
366
|
+
Example: `Venue.version(42).validatable?`
|
367
|
+
|
368
|
+
Tests whether the current configuration of the schema has a validation defined.
|
369
|
+
|
370
|
+
### `register`
|
371
|
+
|
372
|
+
Example: `Venue.register`
|
373
|
+
|
374
|
+
Registers the media type to the registry.
|
375
|
+
|
376
|
+
### `view`
|
377
|
+
|
378
|
+
Example: `Venue.view('create')`
|
379
|
+
|
380
|
+
Returns a schema validator configured with the specified view.
|
381
|
+
|
382
|
+
### `version`
|
383
|
+
|
384
|
+
Example: `Venue.version(42)`
|
385
|
+
|
386
|
+
Returns a schema validator configured with the specified version.
|
387
|
+
|
388
|
+
### `suffix`
|
389
|
+
|
390
|
+
Example: `Venue.suffix(:json)`
|
391
|
+
|
392
|
+
Returns a schema validator configured with the specified suffix.
|
393
|
+
|
394
|
+
### `identifier`
|
395
|
+
|
396
|
+
Example: `Venue.version(2).identifier` (returns `'application/vnd.application.venue.v2'`)
|
397
|
+
|
398
|
+
Returns the IANA compatible [Media Type Identifier](https://en.wikipedia.org/wiki/Media_type) for the configured schema.
|
399
|
+
|
400
|
+
### `available_validations`
|
401
|
+
|
402
|
+
Example: `Venue.available_validations`
|
403
|
+
|
404
|
+
Returns a list of all the schemas that are defined.
|
405
|
+
|
406
|
+
## Ensuring Your MediaTypes Work
|
407
|
+
|
408
|
+
### Overview & Rationale
|
409
|
+
|
410
|
+
If the MediaTypes you create enforce a specification you _do not expect them to_, it will cause problems that will be very difficult to fix, as other code, which utilises your MediaType, would break when you change the specification. This is because the faulty MediaType definition will start to make other code dependent on the specification it defines. For example, consider what would happen if you release a MediaType which defines an attribute `foo` to be a `String`, and run a server which defines such a specification. Later, you realise you _actually_ wanted `foo` to be `Numeric`. What can you do?
|
411
|
+
|
412
|
+
Well, during this time, other people started to write code which conformed to the specification defined by the faulty MediaType. So, it's going to be extremely difficult to revert your mistake. For this reason, it is vital that, when using this library, your MediaTypes define the _correct_ specification.
|
413
|
+
|
414
|
+
To this end, we provide you with a few avenues to check whether MediaTypes define the specifications you actually intend by checking examples of JSON you expect to be compliant/non-compliant with the MediaType definitions you write out.
|
415
|
+
|
416
|
+
These are as follows:
|
417
|
+
|
418
|
+
1. The library provides [two methods](README.md#media-type-checking-in-test-suites) (`assert_pass` and `assert_fail`), which allow specifying JSON fixtures that are compliant (`assert_pass`) or non-compliant (`assert_fail`).
|
419
|
+
2. The library provides a way to validate those fixtures against the MediaType specification with the [`assert_mediatype`](README.md#media-type-checking-in-test-suites) method.
|
420
|
+
3. The library automatically performs a MediaType's checks defined by (1) the first time an object is validated against the MediaType, and throws an error if any of the checks fail.
|
421
|
+
4. The library provides a way to run the checks carried out by (3) on load, using the method [`assert_sane!`](README.md#validation-checks) so that an application will not run if any of the MediaType's checks don't pass.
|
422
|
+
|
423
|
+
These four options are examined in detail below.
|
424
|
+
|
425
|
+
### MediaType Checking in Test Suites
|
426
|
+
|
427
|
+
The library provides the `assert_mediatype` method, which allows running the checks for a particular `MediaType` within Minitest with `assert_pass` and `assert_fail`.
|
428
|
+
If you are using Minitest, you can make `assert_mediatype` available by calling `include MediaTypes::Testing::Assertions` in the test class (e.g. `Minitest::Runnable`):
|
429
|
+
|
430
|
+
```ruby
|
431
|
+
module Minitest
|
432
|
+
class Test < Minitest::Runnable
|
433
|
+
include MediaTypes::Testing::Assertions
|
434
|
+
end
|
435
|
+
end
|
436
|
+
```
|
437
|
+
|
438
|
+
The example below demonstrates how to use `assert_pass` and `assert_fail` within a MediaType, and how to use the `assert_mediatype` method in MiniTest tests to validate them.
|
439
|
+
|
440
|
+
```ruby
|
441
|
+
class MyMedia
|
442
|
+
include MediaTypes::Dsl
|
443
|
+
|
444
|
+
def self.organisation
|
445
|
+
'acme'
|
446
|
+
end
|
447
|
+
|
448
|
+
use_name 'test'
|
449
|
+
|
450
|
+
validations do
|
451
|
+
# Using "any Numeric" this MediaType doesn't care what key names you use.
|
452
|
+
# However, it does care that those keys point to a Numeric value.
|
453
|
+
any Numeric
|
454
|
+
|
455
|
+
assert_pass '{"foo": 42}'
|
456
|
+
assert_pass <<-FIXTURE
|
457
|
+
{ "foo": 42, "bar": 43 }
|
458
|
+
FIXTURE
|
459
|
+
|
460
|
+
# The keyword "any" means there are no required keys, so having no keys should also pass.
|
461
|
+
assert_pass '{}'
|
462
|
+
|
463
|
+
# This MediaType should not accept anything other then a Numeric value.
|
464
|
+
assert_fail <<-FIXTURE
|
465
|
+
{ "foo": { "bar": "string" } }
|
466
|
+
FIXTURE
|
467
|
+
assert_fail '{"foo": {}}'
|
468
|
+
assert_fail '{"foo": null}'
|
469
|
+
assert_fail '{"foo": [42]}'
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
class MyMediaTest < Minitest::Test
|
474
|
+
include MediaTypes::Testing::Assertions
|
475
|
+
|
476
|
+
def test_mediatype_specification
|
477
|
+
assert_mediatype MyMedia
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
class MyMediaTest < Minitest::Test
|
482
|
+
include MediaTypes::Testing::Assertions
|
483
|
+
|
484
|
+
def test_mediatype_specification
|
485
|
+
assert_mediatype MyMedia
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
```
|
490
|
+
|
491
|
+
### Testing Without Minitest
|
492
|
+
|
493
|
+
If you are using another testing framework, you will not be able to use the `assert_mediatype` method. Instead, you can test your MediaTypes by using the `assert_sane!` method (documented below) and rescuing the errors it will throw when it fails. The snippet below shows an example adaptation for MiniTest, which you can use as a guide.
|
494
|
+
|
342
495
|
```ruby
|
343
|
-
|
344
|
-
|
496
|
+
def test_mediatype(mediatype)
|
497
|
+
mediatype.assert_sane!
|
498
|
+
assert mediatype.media_type_validations.scheme.asserted_sane?
|
499
|
+
rescue MediaTypes::AssertionError => e
|
500
|
+
flunk e.message
|
501
|
+
end
|
502
|
+
end
|
503
|
+
```
|
504
|
+
|
505
|
+
### Validation Checks
|
345
506
|
|
346
|
-
|
347
|
-
|
507
|
+
The `assert_pass` and `assert_fail` methods take a JSON string (as shown below). The first time the `validate!` method is called on a MediaType, the assertions for that media type are run.
|
508
|
+
This is done as a last line of defence against introducing faulty MediaTypes into your software. Ideally, you want to carry out these checks on load rather than on a running application. This functionality is provided by the `assert_sane!` method, which can be called on a particular MediaType:
|
509
|
+
|
510
|
+
```ruby
|
511
|
+
MyMedia.assert_sane!
|
512
|
+
# true
|
348
513
|
```
|
349
514
|
|
350
|
-
|
515
|
+
### Intermediate Checks
|
351
516
|
|
352
|
-
|
353
|
-
|
517
|
+
The fixtures provided to the `assert_pass` and `assert_fail` methods are evaluated within the context of the block they are placed in. It's therefore possible to write a test for a (complex) optional attribute, without that test cluttering the fixtures for the entire mediatype.
|
518
|
+
|
519
|
+
```ruby
|
520
|
+
class MyMedia
|
521
|
+
include MediaTypes::Dsl
|
522
|
+
|
523
|
+
expect_string_keys
|
524
|
+
|
525
|
+
def self.organisation
|
526
|
+
'acme'
|
527
|
+
end
|
528
|
+
|
529
|
+
use_name 'test'
|
530
|
+
|
531
|
+
validations do
|
532
|
+
attribute :foo, Hash, optional: true do
|
533
|
+
attribute :bar, Numeric
|
534
|
+
|
535
|
+
# This passes, since in this context the "bar" key is required to have a Numeric value.
|
536
|
+
assert_pass '{"bar": 42}'
|
537
|
+
end
|
538
|
+
attribute :rep, Numeric
|
539
|
+
|
540
|
+
# This passes, since the attribute "foo" is optional.
|
541
|
+
assert_pass '{"rep": 42}'
|
542
|
+
end
|
543
|
+
end
|
544
|
+
```
|
545
|
+
|
546
|
+
## Key Type Validation
|
547
|
+
|
548
|
+
When interacting with Ruby objects defined by your MediaType, you want to avoid getting `nil` values, just because the the wrong key type is being used (e.g. `obj['foo']` instead of `obj[:foo]`).
|
549
|
+
To this end, the library provides the ability to specify the expected type of keys in a MediaType; by default symbol keys are expected.
|
550
|
+
|
551
|
+
### Setting Key Type Expectations
|
552
|
+
|
553
|
+
Key type expectations can be set at the module level. Each MediaType within this module will inherit the expectation set by that module.
|
554
|
+
|
555
|
+
```ruby
|
556
|
+
module Acme
|
557
|
+
MediaTypes.expect_string_keys(self)
|
558
|
+
|
559
|
+
# The MyMedia class expects string keys, as inherited from the Acme module.
|
560
|
+
class MyMedia
|
561
|
+
include MediaTypes::Dsl
|
562
|
+
|
563
|
+
def self.organisation
|
564
|
+
'acme'
|
565
|
+
end
|
566
|
+
|
567
|
+
use_name 'test'
|
568
|
+
|
569
|
+
validations do
|
570
|
+
any Numeric
|
571
|
+
end
|
572
|
+
end
|
573
|
+
end
|
574
|
+
```
|
575
|
+
|
576
|
+
If you validate an object with a different key type than expected, an error will be thrown:
|
577
|
+
|
578
|
+
```ruby
|
579
|
+
Acme::MyMedia.validate! { "something": 42 }
|
580
|
+
# => passes, because all keys are a string
|
581
|
+
|
582
|
+
Acme::MyMedia.validate! { something: 42 }
|
583
|
+
# => throws a ValidationError , because 'something' is a symbol key
|
354
584
|
```
|
355
585
|
|
356
|
-
|
357
|
-
Load the `actionpack` integration and call `.register` on all the media types you want to be available in Rails. You can do this in the `mime_types` initializer, or anywhere before your controllers are instantiated. Yes, the symbol (by default `<type>_v<version>_<suffix>`) can now be used in your `format` blocks, or as extension in the url.
|
586
|
+
## Overriding Key Type Expectations
|
358
587
|
|
359
|
-
|
588
|
+
A key type expectation set by a Module can be overridden by calling either `expect_symbol_keys` or `expect_string_keys` inside the MediaType class.
|
360
589
|
|
361
590
|
```ruby
|
362
|
-
|
591
|
+
module Acme
|
592
|
+
MediaTypes.expect_string_keys(self)
|
593
|
+
|
594
|
+
class MyOverridingMedia
|
595
|
+
include MediaTypes::Dsl
|
596
|
+
|
597
|
+
def self.organisation
|
598
|
+
'acme'
|
599
|
+
end
|
363
600
|
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
601
|
+
use_name 'test'
|
602
|
+
|
603
|
+
# Expect keys to be symbols
|
604
|
+
expect_symbol_keys
|
605
|
+
|
606
|
+
validations do
|
607
|
+
any Numeric
|
608
|
+
end
|
609
|
+
end
|
610
|
+
end
|
611
|
+
```
|
612
|
+
|
613
|
+
Now the MediaType throws an error when string keys are used.
|
614
|
+
|
615
|
+
```ruby
|
616
|
+
Acme::MyOverridingMedia.validate! { something: 42 }
|
617
|
+
# => passes, because all keys are a symbol
|
618
|
+
|
619
|
+
Acme::MyOverridingMedia.validate! { "something": 42 }
|
620
|
+
# => throws a ValidationError , because 'something' is a string key
|
368
621
|
```
|
369
622
|
|
370
|
-
|
623
|
+
### Setting The JSON Parser With The Wrong Key Type
|
371
624
|
|
372
|
-
|
373
|
-
Load the `http` integration and call `.register` on all media types you want to be able to serialize and deserialize. The media type validations will run both before serialization and after deserialization.
|
625
|
+
If you parse JSON with the wrong key type, as shown below, the resultant object will fail the validations.
|
374
626
|
|
375
|
-
|
627
|
+
```ruby
|
628
|
+
class MyMedia
|
629
|
+
include MediaTypes::Dsl
|
630
|
+
|
631
|
+
def self.organisation
|
632
|
+
'acme'
|
633
|
+
end
|
634
|
+
|
635
|
+
use_name 'test'
|
636
|
+
|
637
|
+
# Expect keys to be symbols
|
638
|
+
expect_symbol_keys
|
639
|
+
|
640
|
+
validations do
|
641
|
+
any Numeric
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
json = JSON.parse('{"foo": {}}', { symbolize_names: false })
|
646
|
+
# If MyMedia expects symbol keys
|
647
|
+
MyMedia.valid?(json)
|
648
|
+
# Returns false
|
649
|
+
```
|
376
650
|
|
377
651
|
## Related
|
378
652
|
|
379
|
-
- [`MediaTypes::Serialization`](https://github.com/XPBytes/media_types-serialization): :cyclone: Add media types supported serialization
|
380
|
-
- [`MediaTypes::Validation`](https://github.com/XPBytes/media_types-validation): :heavy_exclamation_mark: Response validations according to a media-type
|
653
|
+
- [`MediaTypes::Serialization`](https://github.com/XPBytes/media_types-serialization): :cyclone: Add media types supported serialization to Rails.
|
381
654
|
|
382
655
|
## Development
|
383
656
|
|