lib/jsonapi/response_document.rb
# frozen_string_literal: true
module JSONAPI
class ResponseDocument
attr_reader :serialized_results
def initialize(options = {})
@serialized_results = []
@result_codes = []
@error_results = []
@global_errors = []
@options = options
@top_level_meta = @options.fetch(:base_meta, {})
@top_level_links = @options.fetch(:base_links, {})
@key_formatter = @options.fetch(:key_formatter, JSONAPI.configuration.key_formatter)
end
def has_errors?
@error_results.length.positive? || @global_errors.length.positive?
end
def add_result(result, operation)
if result.is_a?(JSONAPI::ErrorsOperationResult)
# Clear any serialized results
@serialized_results = []
# In JSONAPI v1 we only have one operation so all errors can be kept together
result.errors.each do |error|
add_global_error(error)
end
else
@serialized_results.push result.to_hash(operation.options[:serializer])
@result_codes.push result.code.to_i
update_links(operation.options[:serializer], result)
update_meta(result)
end
end
def add_global_error(error)
@global_errors.push error
end
def contents
if has_errors?
return { 'errors' => @global_errors }
else
hash = @serialized_results[0]
meta = top_level_meta
hash.merge!('meta' => meta) unless meta.empty?
links = top_level_links
hash.merge!('links' => links) unless links.empty?
return hash
end
end
def status
status_codes = if has_errors?
@global_errors.collect do |error|
error.status.to_i
end
else
@result_codes
end
# Count the unique status codes
counts = status_codes.each_with_object(Hash.new(0)) { |code, counts| counts[code] += 1 }
# if there is only one status code we can return that
return counts.keys[0].to_i if counts.length == 1
# :nocov: not currently used
# if there are many we should return the highest general code, 200, 400, 500 etc.
max_status = 0
status_codes.each do |status|
code = status.to_i
max_status = code if max_status < code
end
return (max_status / 100).floor * 100
# :nocov:
end
private
def update_meta(result)
@top_level_meta.merge!(result.meta)
if JSONAPI.configuration.top_level_meta_include_record_count && result.respond_to?(:record_count)
@top_level_meta[JSONAPI.configuration.top_level_meta_record_count_key] = result.record_count
end
if JSONAPI.configuration.top_level_meta_include_page_count && result.respond_to?(:page_count)
@top_level_meta[JSONAPI.configuration.top_level_meta_page_count_key] = result.page_count
end
if result.warnings.any?
@top_level_meta[:warnings] = result.warnings.collect do |warning|
warning.to_hash
end
end
end
def top_level_meta
@top_level_meta.as_json.deep_transform_keys { |key| @key_formatter.format(key) }
end
def update_links(serializer, result)
@top_level_links.merge!(result.links)
# Build pagination links
if result.is_a?(JSONAPI::ResourceSetOperationResult) ||
result.is_a?(JSONAPI::ResourcesSetOperationResult) ||
result.is_a?(JSONAPI::RelatedResourcesSetOperationResult)
result.pagination_params.each_pair do |link_name, params|
if result.is_a?(JSONAPI::RelatedResourcesSetOperationResult)
relationship = result.source_resource.class._relationships[result._type.to_sym]
unless relationship.exclude_link?(link_name)
link = serializer.link_builder.relationships_related_link(result.source_resource, relationship, query_params(params))
end
else
unless serializer.link_builder.primary_resource_klass.exclude_link?(link_name)
link = serializer.link_builder.query_link(query_params(params))
end
end
@top_level_links[link_name] = link unless link.blank?
end
end
end
def top_level_links
@top_level_links.deep_transform_keys { |key| @key_formatter.format(key) }
end
def query_params(params)
query_params = {}
query_params[:page] = params
request = @options[:request]
if request.params[:fields]
query_params[:fields] = request.params[:fields].respond_to?(:to_unsafe_hash) ? request.params[:fields].to_unsafe_hash : request.params[:fields]
end
query_params[:include] = request.params[:include] if request.params[:include]
query_params[:sort] = request.params[:sort] if request.params[:sort]
if request.params[:filter]
query_params[:filter] = request.params[:filter].respond_to?(:to_unsafe_hash) ? request.params[:filter].to_unsafe_hash : request.params[:filter]
end
query_params
end
end
end