mirror of
https://github.com/ditkrg/jsonapi-deserializable.git
synced 2026-01-22 22:06:47 +00:00
Initial commit
This commit is contained in:
commit
2443af13cb
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
*.gem
|
||||||
|
*.rbc
|
||||||
|
/.config
|
||||||
|
/coverage/
|
||||||
|
/InstalledFiles
|
||||||
|
/pkg/
|
||||||
|
/spec/reports/
|
||||||
|
/spec/examples.txt
|
||||||
|
/test/tmp/
|
||||||
|
/test/version_tmp/
|
||||||
|
/tmp/
|
||||||
|
|
||||||
|
## Specific to RubyMotion:
|
||||||
|
.dat*
|
||||||
|
.repl_history
|
||||||
|
build/
|
||||||
|
|
||||||
|
## Documentation cache and generated files:
|
||||||
|
/.yardoc/
|
||||||
|
/_yardoc/
|
||||||
|
/doc/
|
||||||
|
/rdoc/
|
||||||
|
|
||||||
|
## Environment normalization:
|
||||||
|
/.bundle/
|
||||||
|
/vendor/bundle
|
||||||
|
/lib/bundler/man/
|
||||||
|
|
||||||
|
Gemfile.lock
|
||||||
|
.ruby-version
|
||||||
|
.ruby-gemset
|
||||||
|
|
||||||
|
# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
|
||||||
|
.rvmrc
|
||||||
12
.travis.yml
Normal file
12
.travis.yml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
language: ruby
|
||||||
|
sudo: false
|
||||||
|
before_install:
|
||||||
|
- bundle update
|
||||||
|
rvm:
|
||||||
|
- 2.1
|
||||||
|
- 2.2
|
||||||
|
- 2.3.0
|
||||||
|
- ruby-head
|
||||||
|
matrix:
|
||||||
|
allow_failures:
|
||||||
|
- rvm: ruby-head
|
||||||
234
README.md
Normal file
234
README.md
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
# jsonapi-deserializable
|
||||||
|
Ruby gem for deserializing [JSON API](http://jsonapi.org) payloads into custom
|
||||||
|
hashes.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
[](https://badge.fury.io/rb/jsonapi-deserializable)
|
||||||
|
[](http://travis-ci.org/jsonapi-rb/deserializable?branch=master)
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Usage/Examples](#usageexamples)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Common methods](#common-methods)
|
||||||
|
- [`JSONAPI::Deserializable::Resource` DSL](#jsonapideserializableresource-dsl)
|
||||||
|
- [`JSONAPI::Deserializable::Relationship` DSL](#jsonapideserializablerelationship-dsl)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
```ruby
|
||||||
|
# In Gemfile
|
||||||
|
gem 'jsonapi-deserializable'
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```
|
||||||
|
$ bundle
|
||||||
|
```
|
||||||
|
or manually via
|
||||||
|
```
|
||||||
|
$ gem install jsonapi-deserializable
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage/Examples
|
||||||
|
|
||||||
|
First, require the gem:
|
||||||
|
```ruby
|
||||||
|
require 'jsonapi/deserializable'
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, define some resource/relationship deserializable classes:
|
||||||
|
|
||||||
|
### Resource Example
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class DeserializablePost < JSONAPI::Deserializable::Resource
|
||||||
|
type
|
||||||
|
attribute :title
|
||||||
|
attribute :date { |date| field date: DateTime.parse(date) }
|
||||||
|
has_one :author do |rel, id, type|
|
||||||
|
field author_id: id
|
||||||
|
field author_type: type
|
||||||
|
end
|
||||||
|
has_many :comments do |rel, ids, types|
|
||||||
|
field comment_ids: ids
|
||||||
|
field comment_types: types.map do |type|
|
||||||
|
camelize(singularize(type))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
which can then be used to deserialize post payloads:
|
||||||
|
```ruby
|
||||||
|
DeserializablePost.(payload)
|
||||||
|
# => {
|
||||||
|
# id: '1',
|
||||||
|
# title: 'Title',
|
||||||
|
# date: #<DateTime: 2016-01-10T02:30:00+00:00 ((2457398j,9000s,0n),+0s,2299161j)>,
|
||||||
|
# author_id: '1337',
|
||||||
|
# author_type: 'users',
|
||||||
|
# comment_ids: ['123', '234', '345']
|
||||||
|
# comment_types: ['Comment', 'Comment', 'Comment']
|
||||||
|
# }
|
||||||
|
```
|
||||||
|
|
||||||
|
### Relationship Example
|
||||||
|
|
||||||
|
```ruby
|
||||||
|
class DeserializablePostComments < JSONAPI::Deserializable::Relationship
|
||||||
|
has_many do |rel, ids, types|
|
||||||
|
field comment_ids: ids
|
||||||
|
field comment_types: types.map do |ri|
|
||||||
|
camelize(singularize(type))
|
||||||
|
end
|
||||||
|
field comments_meta: rel['meta']
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
```ruby
|
||||||
|
DeserializablePostComments.(payload)
|
||||||
|
# => {
|
||||||
|
# comment_ids: ['123', '234', '345']
|
||||||
|
# comment_types: ['Comment', 'Comment', 'Comment']
|
||||||
|
# }
|
||||||
|
```
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
Whether deserializaing a resource or a relationship, the base idea is the same:
|
||||||
|
for every part of the payload, simply declare the fields you want to build from
|
||||||
|
their value. You can create as many fields as you want out of any one part of
|
||||||
|
the payload.
|
||||||
|
|
||||||
|
It works according to a whitelisting mechanism: should the corresponding part of
|
||||||
|
the payload not be present, the fields will simply not be created on the result
|
||||||
|
hash.
|
||||||
|
|
||||||
|
Note however that the library expects well formed JSONAPI payloads (which you
|
||||||
|
can ensure using, for instance,
|
||||||
|
[jsonapi-parser](https://github.com/beauby/jsonapi/tree/master/parser)),
|
||||||
|
and that deserialization does not substitute itself to validation of the
|
||||||
|
resulting hash (which you can handle using, for instance,
|
||||||
|
[dry-validation](http://dry-rb.org/gems/dry-validation/)).
|
||||||
|
|
||||||
|
### Common Methods
|
||||||
|
|
||||||
|
+ `::field(hash)`
|
||||||
|
|
||||||
|
The `field` DSL method is the base of jsonapi-deserializable. It simply declares
|
||||||
|
a field of the result hash, with its value. The syntax is:
|
||||||
|
```ruby
|
||||||
|
field key: value
|
||||||
|
```
|
||||||
|
|
||||||
|
It is mainly used within the following DSL contexts, but can be used outside of
|
||||||
|
any to declare custom non payload-related fields.
|
||||||
|
|
||||||
|
+ `#initialize(payload)`
|
||||||
|
|
||||||
|
Build a deserializable instance, ready to be deserialized by calling `#to_h`.
|
||||||
|
|
||||||
|
+ `#to_h`
|
||||||
|
|
||||||
|
In order to deserialize a payload, simply do:
|
||||||
|
```ruby
|
||||||
|
DeserializablePost.new(payload).to_h
|
||||||
|
```
|
||||||
|
or use the shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
DeserializablePost.(payload)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `JSONAPI::Deserializable::Resource` DSL
|
||||||
|
|
||||||
|
+ `::type(&block)`
|
||||||
|
```ruby
|
||||||
|
type do |type|
|
||||||
|
field my_type_field: type
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
type
|
||||||
|
```
|
||||||
|
|
||||||
|
+ `::id(&block)`
|
||||||
|
```ruby
|
||||||
|
id do |id|
|
||||||
|
field my_id_field: id
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
id
|
||||||
|
```
|
||||||
|
|
||||||
|
+ `::attribute(key, &block)`
|
||||||
|
```ruby
|
||||||
|
attribute :title do |title|
|
||||||
|
field my_title_field: title
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
attribute :title
|
||||||
|
```
|
||||||
|
|
||||||
|
+ `::has_one(key, &block)`
|
||||||
|
```ruby
|
||||||
|
has_one :author do |rel, id, type|
|
||||||
|
field my_author_type_field: type
|
||||||
|
field my_author_id_field: id
|
||||||
|
field my_author_meta_field: rel['meta']
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
has_one :author
|
||||||
|
```
|
||||||
|
Note: this creates a field `:author` with value the whole relationship hash.
|
||||||
|
|
||||||
|
+ `::has_many(key, &block)`
|
||||||
|
```ruby
|
||||||
|
has_many :comments do |rel, ids, types|
|
||||||
|
field my_comment_types_field: types
|
||||||
|
field my_comment_ids_field: ids
|
||||||
|
field my_comment_meta_field: rel['meta']
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Shorthand syntax:
|
||||||
|
```ruby
|
||||||
|
has_many :comments
|
||||||
|
```
|
||||||
|
Note: this creates a field `:comments` with value the whole relationship hash.
|
||||||
|
|
||||||
|
### `JSONAPI::Deserializable::Relationship` DSL
|
||||||
|
|
||||||
|
+ `::has_one(key, &block)`
|
||||||
|
```ruby
|
||||||
|
has_one do |rel, id, type|
|
||||||
|
field my_relationship_id_field: id
|
||||||
|
field my_relationship_type_field: type
|
||||||
|
field my_relationship_meta_field: rel['meta']
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
+ `has_many(key, &block)`
|
||||||
|
```ruby
|
||||||
|
has_many do |rel, ids, types|
|
||||||
|
field my_relationship_ids_field: ids
|
||||||
|
field my_relationship_types_field: types
|
||||||
|
field my_relationship_meta_field: rel['meta']
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
jsonapi-deserializable is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
||||||
9
Rakefile
Normal file
9
Rakefile
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
require 'bundler/gem_tasks'
|
||||||
|
require 'rspec/core/rake_task'
|
||||||
|
|
||||||
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||||
|
t.pattern = Dir.glob('spec/**/*_spec.rb')
|
||||||
|
end
|
||||||
|
|
||||||
|
task default: :test
|
||||||
|
task test: :spec
|
||||||
19
jsonapi-deserializable.gemspec
Normal file
19
jsonapi-deserializable.gemspec
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
version = File.read(File.expand_path('../VERSION', __FILE__)).strip
|
||||||
|
|
||||||
|
Gem::Specification.new do |spec|
|
||||||
|
spec.name = 'jsonapi-deserializable'
|
||||||
|
spec.version = version
|
||||||
|
spec.author = 'Lucas Hosseini'
|
||||||
|
spec.email = 'lucas.hosseini@gmail.com'
|
||||||
|
spec.summary = 'Deserialize JSON API payloads.'
|
||||||
|
spec.description = 'DSL for deserializing incoming JSON API payloads ' \
|
||||||
|
'into custom hashes.'
|
||||||
|
spec.homepage = 'https://github.com/jsonapi-rb/deserializable'
|
||||||
|
spec.license = 'MIT'
|
||||||
|
|
||||||
|
spec.files = Dir['README.md', 'lib/**/*']
|
||||||
|
spec.require_path = 'lib'
|
||||||
|
|
||||||
|
spec.add_development_dependency 'rake', '>=0.9'
|
||||||
|
spec.add_development_dependency 'rspec', '~>3.4'
|
||||||
|
end
|
||||||
2
lib/jsonapi/deserializable.rb
Normal file
2
lib/jsonapi/deserializable.rb
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
require 'jsonapi/deserializable/relationship'
|
||||||
|
require 'jsonapi/deserializable/resource'
|
||||||
51
lib/jsonapi/deserializable/relationship.rb
Normal file
51
lib/jsonapi/deserializable/relationship.rb
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
require 'jsonapi/deserializable/relationship_dsl'
|
||||||
|
|
||||||
|
module JSONAPI
|
||||||
|
module Deserializable
|
||||||
|
class Relationship
|
||||||
|
include RelationshipDSL
|
||||||
|
|
||||||
|
class << self
|
||||||
|
attr_accessor :has_one_block, :has_many_block
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.inherited(klass)
|
||||||
|
klass.has_one_block = has_one_block
|
||||||
|
klass.has_many_block = has_many_block
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.call(payload)
|
||||||
|
new(payload).to_h
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(payload)
|
||||||
|
@document = payload
|
||||||
|
@data = payload['data']
|
||||||
|
deserialize!
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_h
|
||||||
|
@hash
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def deserialize!
|
||||||
|
@hash = {}
|
||||||
|
if @data.is_a?(Array)
|
||||||
|
ids = @data.map { |ri| ri['id'] }
|
||||||
|
types = @data.map { |ri| ri['type'] }
|
||||||
|
instance_exec(@document, ids, types, &self.class.has_many_block)
|
||||||
|
else
|
||||||
|
id = @data && @data['id']
|
||||||
|
type = @data && @data['type']
|
||||||
|
instance_exec(@document, id, type, &self.class.has_one_block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def field(hash)
|
||||||
|
@hash.merge!(hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
21
lib/jsonapi/deserializable/relationship_dsl.rb
Normal file
21
lib/jsonapi/deserializable/relationship_dsl.rb
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
module JSONAPI
|
||||||
|
module Deserializable
|
||||||
|
module RelationshipDSL
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def has_one(&block)
|
||||||
|
block ||= proc { |rel| field key.to_sym => rel }
|
||||||
|
self.has_one_block = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_many(&block)
|
||||||
|
block ||= proc { |rel| field key.to_sym => rel }
|
||||||
|
self.has_many_block = block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
110
lib/jsonapi/deserializable/resource.rb
Normal file
110
lib/jsonapi/deserializable/resource.rb
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
require 'jsonapi/deserializable/resource_dsl'
|
||||||
|
|
||||||
|
module JSONAPI
|
||||||
|
module Deserializable
|
||||||
|
class Resource
|
||||||
|
include ResourceDSL
|
||||||
|
|
||||||
|
class << self
|
||||||
|
attr_accessor :type_block, :id_block
|
||||||
|
attr_accessor :attr_blocks
|
||||||
|
attr_accessor :has_one_rel_blocks, :has_many_rel_blocks
|
||||||
|
end
|
||||||
|
|
||||||
|
self.attr_blocks = {}
|
||||||
|
self.has_one_rel_blocks = {}
|
||||||
|
self.has_many_rel_blocks = {}
|
||||||
|
|
||||||
|
def self.inherited(klass)
|
||||||
|
super
|
||||||
|
klass.type_block = type_block
|
||||||
|
klass.id_block = id_block
|
||||||
|
klass.attr_blocks = attr_blocks.dup
|
||||||
|
klass.has_one_rel_blocks = has_one_rel_blocks.dup
|
||||||
|
klass.has_many_rel_blocks = has_many_rel_blocks.dup
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.call(payload)
|
||||||
|
new(payload).to_h
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(payload)
|
||||||
|
@document = payload
|
||||||
|
@data = @document['data']
|
||||||
|
@type = @data['type']
|
||||||
|
@id = @data['id']
|
||||||
|
@attributes = @data['attributes'] || {}
|
||||||
|
@relationships = @data['relationships'] || {}
|
||||||
|
deserialize!
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_h
|
||||||
|
@hash
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def deserialize!
|
||||||
|
@hash = {}
|
||||||
|
deserialize_type!
|
||||||
|
deserialize_id!
|
||||||
|
deserialize_attrs!
|
||||||
|
deserialize_rels!
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_type!
|
||||||
|
return unless @type && self.class.type_block
|
||||||
|
instance_exec(@type, &self.class.type_block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_id!
|
||||||
|
return unless @id && self.class.id_block
|
||||||
|
instance_exec(@id, &self.class.id_block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_attrs!
|
||||||
|
self.class.attr_blocks.each do |attr, block|
|
||||||
|
next unless @attributes.key?(attr)
|
||||||
|
instance_exec(@attributes[attr], &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_rels!
|
||||||
|
deserialize_has_one_rels!
|
||||||
|
deserialize_has_many_rels!
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_has_one_rels!
|
||||||
|
self.class.has_one_rel_blocks.each do |key, block|
|
||||||
|
rel = @relationships[key]
|
||||||
|
next unless rel && (rel['data'].nil? || rel['data'].is_a?(Hash))
|
||||||
|
deserialize_has_one_rel!(rel, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_has_one_rel!(rel, &block)
|
||||||
|
id = rel['data'] && rel['data']['id']
|
||||||
|
type = rel['data'] && rel['data']['type']
|
||||||
|
instance_exec(rel, id, type, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_has_many_rels!
|
||||||
|
self.class.has_many_rel_blocks.each do |key, block|
|
||||||
|
rel = @relationships[key]
|
||||||
|
next unless rel && rel['data'].is_a?(Array)
|
||||||
|
deserialize_has_many_rel!(rel, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def deserialize_has_many_rel!(rel, &block)
|
||||||
|
ids = rel['data'].map { |ri| ri['id'] }
|
||||||
|
types = rel['data'].map { |ri| ri['type'] }
|
||||||
|
instance_exec(rel, ids, types, &block)
|
||||||
|
end
|
||||||
|
|
||||||
|
def field(hash)
|
||||||
|
@hash.merge!(hash)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
39
lib/jsonapi/deserializable/resource_dsl.rb
Normal file
39
lib/jsonapi/deserializable/resource_dsl.rb
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
module JSONAPI
|
||||||
|
module Deserializable
|
||||||
|
module ResourceDSL
|
||||||
|
def self.included(base)
|
||||||
|
base.extend(ClassMethods)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def type(&block)
|
||||||
|
block ||= proc { |type| field type: type }
|
||||||
|
self.type_block = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def id(&block)
|
||||||
|
block ||= proc { |id| field id: id }
|
||||||
|
self.id_block = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def attribute(key, options = {}, &block)
|
||||||
|
unless block
|
||||||
|
options[:key] ||= key.to_sym
|
||||||
|
block = proc { |attr| field key => attr }
|
||||||
|
end
|
||||||
|
attr_blocks[key.to_s] = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_one(key, &block)
|
||||||
|
block ||= proc { |rel| field key.to_sym => rel }
|
||||||
|
has_one_rel_blocks[key.to_s] = block
|
||||||
|
end
|
||||||
|
|
||||||
|
def has_many(key, &block)
|
||||||
|
block ||= proc { |rel| field key.to_sym => rel }
|
||||||
|
has_many_rel_blocks[key.to_s] = block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
44
spec/deserializable_relationships_spec.rb
Normal file
44
spec/deserializable_relationships_spec.rb
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
require 'jsonapi/deserializable'
|
||||||
|
|
||||||
|
describe JSONAPI::Deserializable::Relationship, '#to_h' do
|
||||||
|
it 'deserializes has_one relationships' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Relationship) do
|
||||||
|
has_one do |rel|
|
||||||
|
field sponsor_id: (rel['data'] && rel['data']['id'])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'data' => {
|
||||||
|
'type' => 'users',
|
||||||
|
'id' => '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = deserializable_klass.(payload)
|
||||||
|
expected = { sponsor_id: '1' }
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deserializes has_many relationships' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Relationship) do
|
||||||
|
has_many do |rel|
|
||||||
|
field post_ids: rel['data'].map { |ri| ri['id'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'data' => [
|
||||||
|
{ 'type' => 'postd', 'id' => '1' },
|
||||||
|
{ 'type' => 'postd', 'id' => '2' },
|
||||||
|
{ 'type' => 'postd', 'id' => '3' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
actual = deserializable_klass.(payload)
|
||||||
|
expected = { post_ids: %w(1 2 3) }
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
132
spec/deserializable_resource_spec.rb
Normal file
132
spec/deserializable_resource_spec.rb
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
require 'jsonapi/deserializable'
|
||||||
|
|
||||||
|
describe JSONAPI::Deserializable::Resource, '#to_h' do
|
||||||
|
before(:all) do
|
||||||
|
@payload = {
|
||||||
|
'data' => {
|
||||||
|
'id' => '1',
|
||||||
|
'type' => 'users',
|
||||||
|
'attributes' => {
|
||||||
|
'name' => 'Name',
|
||||||
|
'address' => 'Address'
|
||||||
|
},
|
||||||
|
'relationships' => {
|
||||||
|
'sponsor' => {
|
||||||
|
'data' => { 'type' => 'users', 'id' => '1337' }
|
||||||
|
},
|
||||||
|
'posts' => {
|
||||||
|
'data' => [
|
||||||
|
{ 'type' => 'posts', 'id' => '123' },
|
||||||
|
{ 'type' => 'posts', 'id' => '234' },
|
||||||
|
{ 'type' => 'posts', 'id' => '345' }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deserializes primary type' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
type { |type| field type: type }
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = { type: 'users' }
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'deserializes primary id when present' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
id { |id| field id: id }
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = { id: '1' }
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not deserialize primary id when absent' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
id { |id| field id: id }
|
||||||
|
end
|
||||||
|
|
||||||
|
payload = {
|
||||||
|
'data' => { 'type' => 'users' }
|
||||||
|
}
|
||||||
|
actual = deserializable_klass.(payload)
|
||||||
|
expected = {}
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'handles attributes' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
attribute(:name) { |name| field username: name }
|
||||||
|
attribute(:address) { |address| field address: address }
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = {
|
||||||
|
username: 'Name',
|
||||||
|
address: 'Address'
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'handles has_one relationships' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
has_one(:sponsor) { |rel| field sponsor_id: rel['data']['id'] }
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = {
|
||||||
|
sponsor_id: '1337'
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'handles has_many relationships' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
has_many(:posts) do |rel|
|
||||||
|
field post_ids: rel['data'].map { |ri| ri['id'] }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = {
|
||||||
|
post_ids: %w(123 234 345)
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'works' do
|
||||||
|
deserializable_klass = Class.new(JSONAPI::Deserializable::Resource) do
|
||||||
|
id
|
||||||
|
attribute(:name) { |name| field username: name }
|
||||||
|
attribute :address
|
||||||
|
has_one :sponsor do |_, id|
|
||||||
|
field sponsor_id: id
|
||||||
|
end
|
||||||
|
has_many :posts do |_, ids|
|
||||||
|
field post_ids: ids
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
actual = deserializable_klass.(@payload)
|
||||||
|
expected = {
|
||||||
|
id: '1',
|
||||||
|
username: 'Name',
|
||||||
|
address: 'Address',
|
||||||
|
sponsor_id: '1337',
|
||||||
|
post_ids: %w(123 234 345)
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(actual).to eq(expected)
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user