From 6e816bf80a67bc411269c10138296f5e1bb890a6 Mon Sep 17 00:00:00 2001 From: Reid Beels Date: Wed, 9 Dec 2015 10:21:54 +0100 Subject: [PATCH] Move Routing section and add to README ToC Promote the Routing section of the README to an H3, move it out of (what looks like) the middle of the Serializer section, and add it to the ToC. --- README.md | 305 +++++++++++++++++++++++++++--------------------------- 1 file changed, 153 insertions(+), 152 deletions(-) diff --git a/README.md b/README.md index afc06d180..262154f7e 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ backed by ActiveRecord models or by custom objects. * [Handling Exceptions] (#handling-exceptions) * [Action Callbacks] (#action-callbacks) * [Serializer] (#serializer) + * [Routing] (#routing) * [Configuration] (#configuration) * [Contributing] (#contributing) * [License] (#license) @@ -1368,7 +1369,158 @@ JSONAPI::ResourceSerializer.new(PostResource, include: include_resources, ).serialize_to_hash(PostResource.new(post, nil)) ``` -#### Routing +#### Formatting + +JR by default uses some simple rules to format (and unformat) an attribute for (de-)serialization. Strings and Integers are output to JSON +as is, and all other values have `.to_s` applied to them. This outputs something in all cases, but it is certainly not +correct for every situation. + +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 +getter (and setter) method on the resource which overrides the attribute and apply the (un-)formatting there. For example: + +```ruby +class PersonResource < JSONAPI::Resource + attributes :name, :email, :last_login_time + + # Setter example + def email=(new_email) + @model.email = new_email.downcase + end + + # Getter example + def last_login_time + @model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s + end +end +``` + +This is simple to implement for a one off situation, but not for example if you want to apply the same formatting rules +to all DateTime fields in your system. Another issue is the attribute on the resource will always return a formatted +response, whether you want it or not. + +##### Value Formatters + +To overcome the above limitations JR uses Value Formatters. Value Formatters allow you to control the way values are +handled for an attribute. The `format` can be set per attribute as it is declared in the resource. For example: + +```ruby +class PersonResource < JSONAPI::Resource + attributes :name, :email, :spoken_languages + attribute :last_login_time, format: :date_with_utc_timezone + + # Getter/Setter for spoken_languages ... +end +``` + +A Value formatter has a `format` and an `unformat` method. Here's the base ValueFormatter and DefaultValueFormatter for +reference: + +```ruby +module JSONAPI + class ValueFormatter < Formatter + class << self + def format(raw_value) + super(raw_value) + end + + def unformat(value) + super(value) + end + ... + end + end +end + +class DefaultValueFormatter < JSONAPI::ValueFormatter + class << self + def format(raw_value) + case raw_value + when String, Integer + return raw_value + else + return raw_value.to_s + end + end + end +end +``` + +You can also create your own Value Formatter. Value Formatters must be named with the `format` name followed by +`ValueFormatter`, i.e. `DateWithUTCTimezoneValueFormatter` and derive from `JSONAPI::ValueFormatter`. It is +recommended that you create a directory for your formatters, called `formatters`. + +The `format` method is called by the `ResourceSerializer` as is serializing a resource. The format method takes the +`raw_value` parameter. `raw_value` is the value as read from the model. + +The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through +the `unformat` method. The `unformat` method takes a `value`, which is the value as it comes in on the +request. This allows you process the incoming value to alter its state before it is stored in the model. + +###### Use a Different Default Value Formatter + +Another way to handle formatting is to set a different default value formatter. This will affect all attributes that do +not have a `format` set. You can do this by overriding the `default_attribute_options` method for a resource (or a base +resource for a system wide change). + +```ruby + def default_attribute_options + {format: :my_default} + end +``` + +and + +```ruby +class MyDefaultValueFormatter < JSONAPI::ValueFormatter + class << self + def format(raw_value) + case raw_value + when String, Integer + return raw_value + when DateTime + return raw_value.in_time_zone('UTC').to_s + else + return raw_value.to_s + end + end + end +end +``` + +This way all DateTime values will be formatted to display in the UTC timezone. + +#### Key Format + +By default JR uses dasherized keys as per the +[JSON API naming recommendations](http://jsonapi.org/recommendations/#naming). This can be changed by specifying a +different key formatter. + +For example, to use camel cased keys with an initial lowercase character (JSON's default) create an initializer and add +the following: + +```ruby +JSONAPI.configure do |config| + # built in key format options are :underscored_key, :camelized_key and :dasherized_key + config.json_key_format = :camelized_key +end +``` + +This will cause the serializer to use the `CamelizedKeyFormatter`. You can also create your own `KeyFormatter`, for +example: + +```ruby +class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter + class << self + def format(key) + super.camelize(:upper) + end + end +end +``` + +You would specify this in `JSONAPI.configure` as `:upper_camelized`. + +### Routing JR has a couple of helper methods available to assist you with setting up routes. @@ -1535,157 +1687,6 @@ phone_number_contact GET /phone-numbers/:phone_number_id/contact(.:format) co ``` -#### Formatting - -JR by default uses some simple rules to format (and unformat) an attribute for (de-)serialization. Strings and Integers are output to JSON -as is, and all other values have `.to_s` applied to them. This outputs something in all cases, but it is certainly not -correct for every situation. - -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 -getter (and setter) method on the resource which overrides the attribute and apply the (un-)formatting there. For example: - -```ruby -class PersonResource < JSONAPI::Resource - attributes :name, :email, :last_login_time - - # Setter example - def email=(new_email) - @model.email = new_email.downcase - end - - # Getter example - def last_login_time - @model.last_login_time.in_time_zone(@context[:current_user].time_zone).to_s - end -end -``` - -This is simple to implement for a one off situation, but not for example if you want to apply the same formatting rules -to all DateTime fields in your system. Another issue is the attribute on the resource will always return a formatted -response, whether you want it or not. - -##### Value Formatters - -To overcome the above limitations JR uses Value Formatters. Value Formatters allow you to control the way values are -handled for an attribute. The `format` can be set per attribute as it is declared in the resource. For example: - -```ruby -class PersonResource < JSONAPI::Resource - attributes :name, :email, :spoken_languages - attribute :last_login_time, format: :date_with_utc_timezone - - # Getter/Setter for spoken_languages ... -end -``` - -A Value formatter has a `format` and an `unformat` method. Here's the base ValueFormatter and DefaultValueFormatter for -reference: - -```ruby -module JSONAPI - class ValueFormatter < Formatter - class << self - def format(raw_value) - super(raw_value) - end - - def unformat(value) - super(value) - end - ... - end - end -end - -class DefaultValueFormatter < JSONAPI::ValueFormatter - class << self - def format(raw_value) - case raw_value - when String, Integer - return raw_value - else - return raw_value.to_s - end - end - end -end -``` - -You can also create your own Value Formatter. Value Formatters must be named with the `format` name followed by -`ValueFormatter`, i.e. `DateWithUTCTimezoneValueFormatter` and derive from `JSONAPI::ValueFormatter`. It is -recommended that you create a directory for your formatters, called `formatters`. - -The `format` method is called by the `ResourceSerializer` as is serializing a resource. The format method takes the -`raw_value` parameter. `raw_value` is the value as read from the model. - -The `unformat` method is called when processing the request. Each incoming attribute (except `links`) are run through -the `unformat` method. The `unformat` method takes a `value`, which is the value as it comes in on the -request. This allows you process the incoming value to alter its state before it is stored in the model. - -###### Use a Different Default Value Formatter - -Another way to handle formatting is to set a different default value formatter. This will affect all attributes that do -not have a `format` set. You can do this by overriding the `default_attribute_options` method for a resource (or a base -resource for a system wide change). - -```ruby - def default_attribute_options - {format: :my_default} - end -``` - -and - -```ruby -class MyDefaultValueFormatter < JSONAPI::ValueFormatter - class << self - def format(raw_value) - case raw_value - when String, Integer - return raw_value - when DateTime - return raw_value.in_time_zone('UTC').to_s - else - return raw_value.to_s - end - end - end -end -``` - -This way all DateTime values will be formatted to display in the UTC timezone. - -#### Key Format - -By default JR uses dasherized keys as per the -[JSON API naming recommendations](http://jsonapi.org/recommendations/#naming). This can be changed by specifying a -different key formatter. - -For example, to use camel cased keys with an initial lowercase character (JSON's default) create an initializer and add -the following: - -```ruby -JSONAPI.configure do |config| - # built in key format options are :underscored_key, :camelized_key and :dasherized_key - config.json_key_format = :camelized_key -end -``` - -This will cause the serializer to use the `CamelizedKeyFormatter`. You can also create your own `KeyFormatter`, for -example: - -```ruby -class UpperCamelizedKeyFormatter < JSONAPI::KeyFormatter - class << self - def format(key) - super.camelize(:upper) - end - end -end -``` - -You would specify this in `JSONAPI.configure` as `:upper_camelized`. - ## Configuration JR has a few configuration options. Some have already been mentioned above. To set configuration options create an