lib/yaks/reader/json_api.rb in yaks-0.9.0 vs lib/yaks/reader/json_api.rb in yaks-0.10.0
- old
+ new
@@ -1,49 +1,66 @@
module Yaks
module Reader
class JsonAPI
- def call(parsed_json, env = {})
- attributes = parsed_json['data'].first.dup
- links = attributes.delete('links') || {}
- linked = parsed_json['linked'].nil? ? {} : parsed_json['linked'].dup
- embedded = convert_embedded(links, linked)
- Resource.new(
- type: Util.singularize(attributes.delete('type')[/\w+$/]),
+ def call(parsed_json, _env = {})
+ included = parsed_json['included'].nil? ? {} : parsed_json['included'].dup
+
+ if parsed_json['data'].is_a?(Array)
+ CollectionResource.new(
+ attributes: parsed_json['meta'].nil? ? nil : {meta: parsed_json['meta']},
+ members: parsed_json['data'].map { |data| call('data' => data, 'included' => included) }
+ )
+ else
+ attributes = parsed_json['data'].dup
+ links = attributes.delete('links') || {}
+ type = attributes.delete('type')
+ attributes.merge!(attributes.delete('attributes') || {})
+
+ association_links, resource_links = links.partition { |_k, v| v.is_a?(Hash) }
+ embedded = convert_embedded(Hash[association_links], included)
+ links = convert_links(Hash[resource_links])
+
+ Resource.new(
+ type: Util.singularize(type),
attributes: Util.symbolize_keys(attributes),
subresources: embedded,
- links: []
- )
+ links: links
+ )
+ end
end
- def convert_embedded(links, linked)
+ def convert_embedded(links, included)
links.flat_map do |rel, link_data|
- # If this is a compound link, the link_data will contain either
- # * 'type' and 'id' for a one to one
- # * 'type' and 'ids' for a homogeneous to-many relationship
- # * 'data' being an array where each member has 'type' and 'id' for heterogeneous
- if !link_data['type'].nil? && !link_data['id'].nil?
- resource = linked.find{ |item| (item['id'] == link_data['id']) && (item['type'] == link_data['type']) }
- call({'data' => [resource], 'linked' => linked}).with(rels: [rel])
- elsif !link_data['type'].nil? && !link_data['ids'].nil?
- resources = linked.select{ |item| (link_data['ids'].include? item['id']) && (item['type'] == link_data['type']) }
- members = resources.map { |r|
- call({'data' => [r], 'linked' => linked})
- }
+ # A Link doesn't have to contain a `linkage` member.
+ # It can contain URLs instead, or as well, but we are only worried about *embedded* links here.
+ linkage = link_data['linkage']
+ # Resource linkage MUST be represented as one of the following:
+ #
+ # * `null` for empty to-one relationships.
+ # * a "linkage object" for non-empty to-one relationships.
+ # * an empty array ([]) for empty to-many relationships.
+ # * an array of linkage objects for non-empty to-many relationships.
+ if linkage.nil?
+ nil
+ elsif linkage.is_a? Array
CollectionResource.new(
- members: members,
- type: link_data['type'],
- rels: [rel]
+ members: linkage.map { |link|
+ data = included.find{ |item| (item['id'] == link['id']) && (item['type'] == link['type']) }
+ call('data' => data, 'included' => included)
+ },
+ rels: [rel]
)
- elsif link_data['data'].present?
- CollectionResource.new(
- members: link_data['data'].map { |link|
- resource = linked.find{ |item| (item['id'] == link['id']) && (item['type'] == link['type']) }
- call({'data' => [resource], 'linked' => linked})
- },
- rels: [rel]
- )
+ else
+ data = included.find{ |item| (item['id'] == linkage['id']) && (item['type'] == linkage['type']) }
+ call('data' => data, 'included' => included).with(rels: [rel])
end
end.compact
+ end
+
+ def convert_links(links)
+ links.map do |rel, link|
+ Resource::Link.new(rel: rel.to_sym, uri: link)
+ end
end
end
end
end