lib/json_api_client/parsers/parser.rb
module JsonApiClient
module Parsers
class Parser
class << self
def parse(klass, response)
data = response.body.present? ? response.body : {}
ResultSet.new.tap do |result_set|
result_set.record_class = klass
result_set.uri = response.env[:url]
handle_json_api(result_set, data)
handle_data(result_set, data)
handle_errors(result_set, data)
handle_meta(result_set, data)
handle_links(result_set, data)
handle_relationships(result_set, data)
handle_pagination(result_set, data)
handle_included(result_set, data)
end
end
#
# Given a resource hash, returns a Resource.new friendly hash
# which flattens the attributes in w/ id and type.
#
# Example:
#
# Given:
# {
# id: 1.
# type: 'person',
# attributes: {
# first_name: 'Jeff',
# last_name: 'Ching'
# },
# links: {...},
# relationships: {...}
# }
#
# Returns:
# {
# id: 1,
# type: 'person',
# first_name: 'Jeff',
# last_name: 'Ching'
# links: {...},
# relationships: {...}
# }
#
#
def parameters_from_resource(params)
attrs = params.slice('id', 'links', 'meta', 'type', 'relationships')
attrs.merge(params.fetch('attributes', {}))
end
private
def handle_json_api(result_set, data)
result_set.implementation = Implementation.new(data.fetch("jsonapi", {}))
end
def handle_data(result_set, data)
# all data lives under the "data" attribute
results = data.fetch("data", [])
# we will treat everything as an Array
results = [results] unless results.is_a?(Array)
resources = results.compact.map do |res|
resource = result_set.record_class.load(parameters_from_resource(res))
resource.last_result_set = result_set
resource
end
result_set.concat(resources)
end
def handle_errors(result_set, data)
result_set.errors = ErrorCollector.new(data.fetch("errors", []))
end
def handle_meta(result_set, data)
result_set.meta = MetaData.new(data.fetch("meta", {}), result_set.record_class)
end
def handle_links(result_set, data)
result_set.links = Linking::TopLevelLinks.new(result_set.record_class, data.fetch("links", {}))
end
def handle_relationships(result_set, data)
result_set.relationships = Relationships::TopLevelRelations.new(result_set.record_class, data.fetch("relationships", {}))
end
def handle_pagination(result_set, data)
result_set.pages = result_set.record_class.paginator.new(result_set, data)
end
def handle_included(result_set, data)
result_set.included = IncludedData.new(result_set, data.fetch("included", []))
end
end
end
end
end