jsonapi-resources 0.7.0 → 0.7.1.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 32e7bab3bce04e8ef68e0e58fd0274b128d7b68c
4
- data.tar.gz: d12938d652c1ea0c692fea2c940354e673f75678
3
+ metadata.gz: cb58ea800ff6a685353e48ffca57603b1db612d8
4
+ data.tar.gz: 542b9ec812a94328f50204bbbef8743d593c2413
5
5
  SHA512:
6
- metadata.gz: dd1e03599ab80a412cbe06e8d8d3231131a221f3406d82432c05d1b00c38b5002b3f1b30791c23328e613f12638f55ca35177439465ee1359dcb62f96a256057
7
- data.tar.gz: 499fcf89189161652538b1716db928efe228b0db2e0d377012a0f98439463c1ef334cfc18b842a737f71e8c53aa9f2925932035cdbef3573726edcfb780d464b
6
+ metadata.gz: f2ad634e949bce4a5a0f1482dbd66392e97efba3f015a3eb9c3c87b8fe0b7ed0b8bb5e1a2f6dcde3bd228ad64b51de2cd6d12aed9586980e4cadf5aeb59d6acd
7
+ data.tar.gz: 7a4a9275358f79a011b2610e316cd5190beb23e375661ef0508fb65cd3c0b08c7d0bbf751ca0ef37d98a455f842e059feb5d39be70b70b63aa2dc53308bb24ae
data/README.md CHANGED
@@ -34,6 +34,7 @@ backed by ActiveRecord models or by custom objects.
34
34
  * [Handling Exceptions] (#handling-exceptions)
35
35
  * [Action Callbacks] (#action-callbacks)
36
36
  * [Serializer] (#serializer)
37
+ * [Routing] (#routing)
37
38
  * [Configuration] (#configuration)
38
39
  * [Contributing] (#contributing)
39
40
  * [License] (#license)
@@ -114,7 +115,7 @@ generate routes for `index`, `show` and `show_relationship`.
114
115
 
115
116
  ###### Immutable for Readonly
116
117
 
117
- Some resources are read-only and are not to be modified through the API. Declaring a resource as immutable prevents
118
+ Some resources are read-only and are not to be modified through the API. Declaring a resource as immutable prevents
118
119
  creation of routes that allow modification of the resource.
119
120
 
120
121
  ###### Immutable Heterogeneous Collections
@@ -187,7 +188,7 @@ end
187
188
  ##### Fetchable Attributes
188
189
 
189
190
  By default all attributes are assumed to be fetchable. The list of fetchable attributes can be filtered by overriding
190
- the `self.fetchable_fields` method.
191
+ the `fetchable_fields` method.
191
192
 
192
193
  Here's an example that prevents guest users from seeing the `email` field:
193
194
 
@@ -197,7 +198,7 @@ class AuthorResource < JSONAPI::Resource
197
198
  model_name 'Person'
198
199
  has_many :posts
199
200
 
200
- def self.fetchable_fields(context)
201
+ def fetchable_fields
201
202
  if (context[:current_user].guest)
202
203
  super - [:email]
203
204
  else
@@ -365,7 +366,7 @@ end
365
366
  #### Model Hints
366
367
 
367
368
  Resource instances are created from model records. The determination of the correct resource type is performed using a
368
- simple rule based on the model's name. The name is used to find a resource in the same module (as the originating
369
+ simple rule based on the model's name. The name is used to find a resource in the same module (as the originating
369
370
  resource) that matches the name. This usually works quite well, however it can fail when model names do not match
370
371
  resource names. It can also fail when using namespaced models. In this case a `model_hint` can be created to map model
371
372
  names to resources. For example:
@@ -391,7 +392,7 @@ end
391
392
  ```
392
393
 
393
394
  Model hints inherit from parent resources, but are not global in scope. The `model_hint` method accepts `model` and
394
- `resource` named parameters. `model` takes an ActiveRecord class or class name (defaults to the model name), and
395
+ `resource` named parameters. `model` takes an ActiveRecord class or class name (defaults to the model name), and
395
396
  `resource` takes a resource type or a resource class (defaults to the current resource's type).
396
397
 
397
398
  #### Relationships
@@ -449,6 +450,7 @@ The relationship methods (`relationship`, `has_one`, and `has_many`) support the
449
450
  * `acts_as_set` - allows the entire set of related records to be replaced in one operation. Defaults to false if not set.
450
451
  * `polymorphic` - set to true to identify relationships that are polymorphic.
451
452
  * `relation_name` - the name of the relation to use on the model. A lambda may be provided which allows conditional selection of the relation based on the context.
453
+ * `always_include_linkage_data` - if set to true, the relationship includes linkage data. Defaults to false if not set.
452
454
 
453
455
  `to_one` relationships support the additional option:
454
456
  * `foreign_key_on` - defaults to `:self`. To indicate that the foreign key is on the related resource specify `:related`.
@@ -545,8 +547,8 @@ The default value is used as if it came from the request.
545
547
  ##### Applying Filters
546
548
 
547
549
  You may customize how a filter behaves by supplying a callable to the `:apply` option. This callable will be used to
548
- apply that filter. The callable is passed the `records`, which is an `ActiveRecord::Relation`, the `value`, and an
549
- `_options` hash. It is expected to return an `ActiveRecord::Relation`.
550
+ apply that filter. The callable is passed the `records`, which is an `ActiveRecord::Relation`, the `value`, and an
551
+ `_options` hash. It is expected to return an `ActiveRecord::Relation`.
550
552
 
551
553
  This example shows how you can implement different approaches for different filters.
552
554
 
@@ -580,7 +582,7 @@ end
580
582
 
581
583
  ##### Verifying Filters
582
584
 
583
- Because filters typically come straight from the request, it's prudent to verify their values. To do so, provide a
585
+ Because filters typically come straight from the request, it's prudent to verify their values. To do so, provide a
584
586
  callable to the `verify` option. This callable will be passed the `value` and the `context`. Verify should return the
585
587
  verified value, which may be modified.
586
588
 
@@ -599,7 +601,7 @@ verified value, which may be modified.
599
601
 
600
602
  Basic finding by filters is supported by resources. This is implemented in the `find` and `find_by_key` finder methods.
601
603
  Currently this is implemented for `ActiveRecord` based resources. The finder methods rely on the `records` method to get
602
- an `ActiveRecord::Relation` relation. It is therefore possible to override `records` to affect the three find related
604
+ an `ActiveRecord::Relation` relation. It is therefore possible to override `records` to affect the three find related
603
605
  methods.
604
606
 
605
607
  ###### Customizing base records for finder methods
@@ -641,7 +643,7 @@ end
641
643
 
642
644
  ```
643
645
 
644
- For example, you may want raise an error if the user is not authorized to view the related records. See the next
646
+ For example, you may want to raise an error if the user is not authorized to view the related records. See the next
645
647
  section for additional details on raising errors.
646
648
 
647
649
  ```ruby
@@ -730,12 +732,12 @@ like to base the sorting on variables in your context.
730
732
  Example:
731
733
 
732
734
  ```ruby
733
- def self.apply_sort(records, order_options, context = {})
735
+ def self.apply_sort(records, order_options, context = {})
734
736
  if order_options.has?(:trending)
735
737
  records = records.order_by_trending_scope
736
738
  order_options - [:trending]
737
739
  end
738
-
740
+
739
741
  super(records, order_options, context)
740
742
  end
741
743
  ```
@@ -921,7 +923,7 @@ end
921
923
  ```
922
924
 
923
925
  The `meta` method will be called for each resource instance. Override the `meta` method on a resource class to control
924
- the meta information for the resource. If a non empty hash is returned from `meta` this will be serialized. The `meta`
926
+ the meta information for the resource. If a non empty hash is returned from `meta` this will be serialized. The `meta`
925
927
  method is called with an `options` has. The `options` hash will contain the following:
926
928
 
927
929
  * `:serializer` -> the serializer instance
@@ -1041,6 +1043,10 @@ end
1041
1043
 
1042
1044
  Of course you are free to extend this as needed and override action handlers or other methods.
1043
1045
 
1046
+ A jsonapi-controller generator is avaliable
1047
+ ```
1048
+ rails generate jsonapi:controller contact
1049
+ ```
1044
1050
 
1045
1051
  ###### Context
1046
1052
 
@@ -1188,31 +1194,31 @@ Error codes are provided for each error object returned, based on the error. The
1188
1194
 
1189
1195
  ```ruby
1190
1196
  module JSONAPI
1191
- VALIDATION_ERROR = 100
1192
- INVALID_RESOURCE = 101
1193
- FILTER_NOT_ALLOWED = 102
1194
- INVALID_FIELD_VALUE = 103
1195
- INVALID_FIELD = 104
1196
- PARAM_NOT_ALLOWED = 105
1197
- PARAM_MISSING = 106
1198
- INVALID_FILTER_VALUE = 107
1199
- COUNT_MISMATCH = 108
1200
- KEY_ORDER_MISMATCH = 109
1201
- KEY_NOT_INCLUDED_IN_URL = 110
1202
- INVALID_INCLUDE = 112
1203
- RELATION_EXISTS = 113
1204
- INVALID_SORT_CRITERIA = 114
1205
- INVALID_LINKS_OBJECT = 115
1206
- TYPE_MISMATCH = 116
1207
- INVALID_PAGE_OBJECT = 117
1208
- INVALID_PAGE_VALUE = 118
1209
- INVALID_FIELD_FORMAT = 119
1210
- INVALID_FILTERS_SYNTAX = 120
1211
- SAVE_FAILED = 121
1212
- FORBIDDEN = 403
1213
- RECORD_NOT_FOUND = 404
1214
- UNSUPPORTED_MEDIA_TYPE = 415
1215
- LOCKED = 423
1197
+ VALIDATION_ERROR = '100'
1198
+ INVALID_RESOURCE = '101'
1199
+ FILTER_NOT_ALLOWED = '102'
1200
+ INVALID_FIELD_VALUE = '103'
1201
+ INVALID_FIELD = '104'
1202
+ PARAM_NOT_ALLOWED = '105'
1203
+ PARAM_MISSING = '106'
1204
+ INVALID_FILTER_VALUE = '107'
1205
+ COUNT_MISMATCH = '108'
1206
+ KEY_ORDER_MISMATCH = '109'
1207
+ KEY_NOT_INCLUDED_IN_URL = '110'
1208
+ INVALID_INCLUDE = '112'
1209
+ RELATION_EXISTS = '113'
1210
+ INVALID_SORT_CRITERIA = '114'
1211
+ INVALID_LINKS_OBJECT = '115'
1212
+ TYPE_MISMATCH = '116'
1213
+ INVALID_PAGE_OBJECT = '117'
1214
+ INVALID_PAGE_VALUE = '118'
1215
+ INVALID_FIELD_FORMAT = '119'
1216
+ INVALID_FILTERS_SYNTAX = '120'
1217
+ SAVE_FAILED = '121'
1218
+ FORBIDDEN = '403'
1219
+ RECORD_NOT_FOUND = '404'
1220
+ UNSUPPORTED_MEDIA_TYPE = '415'
1221
+ LOCKED = '423'
1216
1222
  end
1217
1223
  ```
1218
1224
 
@@ -1368,7 +1374,158 @@ JSONAPI::ResourceSerializer.new(PostResource, include: include_resources,
1368
1374
  ).serialize_to_hash(PostResource.new(post, nil))
1369
1375
  ```
1370
1376
 
1371
- #### Routing
1377
+ #### Formatting
1378
+
1379
+ JR by default uses some simple rules to format (and unformat) an attribute for (de-)serialization. Strings and Integers are output to JSON
1380
+ as is, and all other values have `.to_s` applied to them. This outputs something in all cases, but it is certainly not
1381
+ correct for every situation.
1382
+
1383
+ If you want to change the way an attribute is (de-)serialized you have a couple of ways. The simplest method is to create a
1384
+ getter (and setter) method on the resource which overrides the attribute and apply the (un-)formatting there. For example:
1385
+
1386
+ ```ruby
1387
+ class PersonResource < JSONAPI::Resource
1388
+ attributes :name, :email, :last_login_time
1389
+
1390
+ # Setter example
1391
+ def email=(new_email)
1392
+ @model.email = new_email.downcase
1393
+ end
1394
+
1395
+ # Getter example
1396
+ def last_login_time
1397
+ @model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s
1398
+ end
1399
+ end
1400
+ ```
1401
+
1402
+ This is simple to implement for a one off situation, but not for example if you want to apply the same formatting rules
1403
+ to all DateTime fields in your system. Another issue is the attribute on the resource will always return a formatted
1404
+ response, whether you want it or not.
1405
+
1406
+ ##### Value Formatters
1407
+
1408
+ To overcome the above limitations JR uses Value Formatters. Value Formatters allow you to control the way values are
1409
+ handled for an attribute. The `format` can be set per attribute as it is declared in the resource. For example:
1410
+
1411
+ ```ruby
1412
+ class PersonResource < JSONAPI::Resource
1413
+ attributes :name, :email, :spoken_languages
1414
+ attribute :last_login_time, format: :date_with_utc_timezone
1415
+
1416
+ # Getter/Setter for spoken_languages ...
1417
+ end
1418
+ ```
1419
+
1420
+ A Value formatter has a `format` and an `unformat` method. Here's the base ValueFormatter and DefaultValueFormatter for
1421
+ reference:
1422
+
1423
+ ```ruby
1424
+ module JSONAPI
1425
+ class ValueFormatter < Formatter
1426
+ class << self
1427
+ def format(raw_value)
1428
+ super(raw_value)
1429
+ end
1430
+
1431
+ def unformat(value)
1432
+ super(value)
1433
+ end
1434
+ ...
1435
+ end
1436
+ end
1437
+ end
1438
+
1439
+ class DefaultValueFormatter < JSONAPI::ValueFormatter
1440
+ class << self
1441
+ def format(raw_value)
1442
+ case raw_value
1443
+ when String, Integer
1444
+ return raw_value
1445
+ else
1446
+ return raw_value.to_s
1447
+ end
1448
+ end
1449
+ end
1450
+ end
1451
+ ```
1452
+
1453
+ You can also create your own Value Formatter. Value Formatters must be named with the `format` name followed by
1454
+ `ValueFormatter`, i.e. `DateWithUTCTimezoneValueFormatter` and derive from `JSONAPI::ValueFormatter`. It is
1455
+ recommended that you create a directory for your formatters, called `formatters`.
1456
+
1457
+ The `format` method is called by the `ResourceSerializer` as is serializing a resource. The format method takes the
1458
+ `raw_value` parameter. `raw_value` is the value as read from the model.
1459
+
1460
+ The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through
1461
+ the `unformat` method. The `unformat` method takes a `value`, which is the value as it comes in on the
1462
+ request. This allows you process the incoming value to alter its state before it is stored in the model.
1463
+
1464
+ ###### Use a Different Default Value Formatter
1465
+
1466
+ Another way to handle formatting is to set a different default value formatter. This will affect all attributes that do
1467
+ not have a `format` set. You can do this by overriding the `default_attribute_options` method for a resource (or a base
1468
+ resource for a system wide change).
1469
+
1470
+ ```ruby
1471
+ def default_attribute_options
1472
+ {format: :my_default}
1473
+ end
1474
+ ```
1475
+
1476
+ and
1477
+
1478
+ ```ruby
1479
+ class MyDefaultValueFormatter < JSONAPI::ValueFormatter
1480
+ class << self
1481
+ def format(raw_value)
1482
+ case raw_value
1483
+ when String, Integer
1484
+ return raw_value
1485
+ when DateTime
1486
+ return raw_value.in_time_zone('UTC').to_s
1487
+ else
1488
+ return raw_value.to_s
1489
+ end
1490
+ end
1491
+ end
1492
+ end
1493
+ ```
1494
+
1495
+ This way all DateTime values will be formatted to display in the UTC timezone.
1496
+
1497
+ #### Key Format
1498
+
1499
+ By default JR uses dasherized keys as per the
1500
+ [JSON API naming recommendations](http://jsonapi.org/recommendations/#naming). This can be changed by specifying a
1501
+ different key formatter.
1502
+
1503
+ For example, to use camel cased keys with an initial lowercase character (JSON's default) create an initializer and add
1504
+ the following:
1505
+
1506
+ ```ruby
1507
+ JSONAPI.configure do |config|
1508
+ # built in key format options are :underscored_key, :camelized_key and :dasherized_key
1509
+ config.json_key_format = :camelized_key
1510
+ end
1511
+ ```
1512
+
1513
+ This will cause the serializer to use the `CamelizedKeyFormatter`. You can also create your own `KeyFormatter`, for
1514
+ example:
1515
+
1516
+ ```ruby
1517
+ class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter
1518
+ class << self
1519
+ def format(key)
1520
+ super.camelize(:upper)
1521
+ end
1522
+ end
1523
+ end
1524
+ ```
1525
+
1526
+ You would specify this in `JSONAPI.configure` as `:upper_camelized`.
1527
+
1528
+ ### Routing
1372
1529
 
1373
1530
  JR has a couple of helper methods available to assist you with setting up routes.
1374
1531
 
@@ -1535,157 +1692,6 @@ phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) co
1535
1692
 
1536
1693
  ```
1537
1694
 
1538
- #### Formatting
1539
-
1540
- JR by default uses some simple rules to format (and unformat) an attribute for (de-)serialization. Strings and Integers are output to JSON
1541
- as is, and all other values have `.to_s` applied to them. This outputs something in all cases, but it is certainly not
1542
- correct for every situation.
1543
-
1544
- If you want to change the way an attribute is (de-)serialized you have a couple of ways. The simplest method is to create a
1545
- getter (and setter) method on the resource which overrides the attribute and apply the (un-)formatting there. For example:
1546
-
1547
- ```ruby
1548
- class PersonResource < JSONAPI::Resource
1549
- attributes :name, :email, :last_login_time
1550
-
1551
- # Setter example
1552
- def email=(new_email)
1553
- @model.email = new_email.downcase
1554
- end
1555
-
1556
- # Getter example
1557
- def last_login_time
1558
- @model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s
1559
- end
1560
- end
1561
- ```
1562
-
1563
- This is simple to implement for a one off situation, but not for example if you want to apply the same formatting rules
1564
- to all DateTime fields in your system. Another issue is the attribute on the resource will always return a formatted
1565
- response, whether you want it or not.
1566
-
1567
- ##### Value Formatters
1568
-
1569
- To overcome the above limitations JR uses Value Formatters. Value Formatters allow you to control the way values are
1570
- handled for an attribute. The `format` can be set per attribute as it is declared in the resource. For example:
1571
-
1572
- ```ruby
1573
- class PersonResource < JSONAPI::Resource
1574
- attributes :name, :email, :spoken_languages
1575
- attribute :last_login_time, format: :date_with_utc_timezone
1576
-
1577
- # Getter/Setter for spoken_languages ...
1578
- end
1579
- ```
1580
-
1581
- A Value formatter has a `format` and an `unformat` method. Here's the base ValueFormatter and DefaultValueFormatter for
1582
- reference:
1583
-
1584
- ```ruby
1585
- module JSONAPI
1586
- class ValueFormatter < Formatter
1587
- class << self
1588
- def format(raw_value)
1589
- super(raw_value)
1590
- end
1591
-
1592
- def unformat(value)
1593
- super(value)
1594
- end
1595
- ...
1596
- end
1597
- end
1598
- end
1599
-
1600
- class DefaultValueFormatter < JSONAPI::ValueFormatter
1601
- class << self
1602
- def format(raw_value)
1603
- case raw_value
1604
- when String, Integer
1605
- return raw_value
1606
- else
1607
- return raw_value.to_s
1608
- end
1609
- end
1610
- end
1611
- end
1612
- ```
1613
-
1614
- You can also create your own Value Formatter. Value Formatters must be named with the `format` name followed by
1615
- `ValueFormatter`, i.e. `DateWithUTCTimezoneValueFormatter` and derive from `JSONAPI::ValueFormatter`. It is
1616
- recommended that you create a directory for your formatters, called `formatters`.
1617
-
1618
- The `format` method is called by the `ResourceSerializer` as is serializing a resource. The format method takes the
1619
- `raw_value` parameter. `raw_value` is the value as read from the model.
1620
-
1621
- The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through
1622
- the `unformat` method. The `unformat` method takes a `value`, which is the value as it comes in on the
1623
- request. This allows you process the incoming value to alter its state before it is stored in the model.
1624
-
1625
- ###### Use a Different Default Value Formatter
1626
-
1627
- Another way to handle formatting is to set a different default value formatter. This will affect all attributes that do
1628
- not have a `format` set. You can do this by overriding the `default_attribute_options` method for a resource (or a base
1629
- resource for a system wide change).
1630
-
1631
- ```ruby
1632
- def default_attribute_options
1633
- {format: :my_default}
1634
- end
1635
- ```
1636
-
1637
- and
1638
-
1639
- ```ruby
1640
- class MyDefaultValueFormatter < JSONAPI::ValueFormatter
1641
- class << self
1642
- def format(raw_value)
1643
- case raw_value
1644
- when String, Integer
1645
- return raw_value
1646
- when DateTime
1647
- return raw_value.in_time_zone('UTC').to_s
1648
- else
1649
- return raw_value.to_s
1650
- end
1651
- end
1652
- end
1653
- end
1654
- ```
1655
-
1656
- This way all DateTime values will be formatted to display in the UTC timezone.
1657
-
1658
- #### Key Format
1659
-
1660
- By default JR uses dasherized keys as per the
1661
- [JSON API naming recommendations](http://jsonapi.org/recommendations/#naming). This can be changed by specifying a
1662
- different key formatter.
1663
-
1664
- For example, to use camel cased keys with an initial lowercase character (JSON's default) create an initializer and add
1665
- the following:
1666
-
1667
- ```ruby
1668
- JSONAPI.configure do |config|
1669
- # built in key format options are :underscored_key, :camelized_key and :dasherized_key
1670
- config.json_key_format = :camelized_key
1671
- end
1672
- ```
1673
-
1674
- This will cause the serializer to use the `CamelizedKeyFormatter`. You can also create your own `KeyFormatter`, for
1675
- example:
1676
-
1677
- ```ruby
1678
- class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter
1679
- class << self
1680
- def format(key)
1681
- super.camelize(:upper)
1682
- end
1683
- end
1684
- end
1685
- ```
1686
-
1687
- You would specify this in `JSONAPI.configure` as `:upper_camelized`.
1688
-
1689
1695
  ## Configuration
1690
1696
 
1691
1697
  JR has a few configuration options. Some have already been mentioned above. To set configuration options create an