Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
305 changes: 153 additions & 152 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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
Expand Down