Skip to content
Merged
Show file tree
Hide file tree
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
4 changes: 2 additions & 2 deletions lib/jsonapi/error_codes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ module JSONAPI
PARAM_NOT_ALLOWED = '105'
PARAM_MISSING = '106'
INVALID_FILTER_VALUE = '107'
COUNT_MISMATCH = '108'
KEY_ORDER_MISMATCH = '109'
KEY_NOT_INCLUDED_IN_URL = '110'
INVALID_INCLUDE = '112'
Expand All @@ -20,6 +19,7 @@ module JSONAPI
INVALID_FIELD_FORMAT = '119'
INVALID_FILTERS_SYNTAX = '120'
SAVE_FAILED = '121'
INVALID_DATA_FORMAT = '122'
FORBIDDEN = '403'
RECORD_NOT_FOUND = '404'
NOT_ACCEPTABLE = '406'
Expand All @@ -36,7 +36,6 @@ module JSONAPI
PARAM_NOT_ALLOWED => 'PARAM_NOT_ALLOWED',
PARAM_MISSING => 'PARAM_MISSING',
INVALID_FILTER_VALUE => 'INVALID_FILTER_VALUE',
COUNT_MISMATCH => 'COUNT_MISMATCH',
KEY_ORDER_MISMATCH => 'KEY_ORDER_MISMATCH',
KEY_NOT_INCLUDED_IN_URL => 'KEY_NOT_INCLUDED_IN_URL',
INVALID_INCLUDE => 'INVALID_INCLUDE',
Expand All @@ -49,6 +48,7 @@ module JSONAPI
INVALID_FIELD_FORMAT => 'INVALID_FIELD_FORMAT',
INVALID_FILTERS_SYNTAX => 'INVALID_FILTERS_SYNTAX',
SAVE_FAILED => 'SAVE_FAILED',
INVALID_DATA_FORMAT => 'INVALID_DATA_FORMAT',
FORBIDDEN => 'FORBIDDEN',
RECORD_NOT_FOUND => 'RECORD_NOT_FOUND',
NOT_ACCEPTABLE => 'NOT_ACCEPTABLE',
Expand Down
24 changes: 13 additions & 11 deletions lib/jsonapi/exceptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ module JSONAPI
module Exceptions
class Error < RuntimeError
def errors
# :nocov:
raise NotImplementedError, "Subclass of Error must implement errors method"
# :nocov:
end
end

Expand Down Expand Up @@ -208,6 +210,17 @@ def errors
end
end

class InvalidDataFormat < Error
def errors
[JSONAPI::Error.new(code: JSONAPI::INVALID_DATA_FORMAT,
status: :bad_request,
title: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.title',
default: 'Invalid data format'),
detail: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.detail',
default: 'Data must be a hash.'))]
end
end

class InvalidLinksObject < Error
def errors
[JSONAPI::Error.new(code: JSONAPI::INVALID_LINKS_OBJECT,
Expand Down Expand Up @@ -324,17 +337,6 @@ def errors
end
end

class CountMismatch < Error
def errors
[JSONAPI::Error.new(code: JSONAPI::COUNT_MISMATCH,
status: :bad_request,
title: I18n.translate('jsonapi-resources.exceptions.count_mismatch.title',
default: 'Count to key mismatch'),
detail: I18n.translate('jsonapi-resources.exceptions.count_mismatch.detail',
default: 'The resource collection does not contain the same number of objects as the number of keys.'))]
end
end

class KeyNotIncludedInURL < Error
attr_accessor :key
def initialize(key)
Expand Down
24 changes: 15 additions & 9 deletions lib/jsonapi/processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class Processor
:replace_fields,
:replace_to_one_relationship,
:replace_polymorphic_to_one_relationship,
:create_to_many_relationship,
:replace_to_many_relationship,
:remove_to_many_relationship,
:create_to_many_relationships,
:replace_to_many_relationships,
:remove_to_many_relationships,
:remove_to_one_relationship,
:operation

Expand Down Expand Up @@ -276,7 +276,7 @@ def replace_polymorphic_to_one_relationship
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
end

def create_to_many_relationship
def create_to_many_relationships
resource_id = params[:resource_id]
relationship_type = params[:relationship_type].to_sym
data = params[:data]
Expand All @@ -287,7 +287,7 @@ def create_to_many_relationship
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
end

def replace_to_many_relationship
def replace_to_many_relationships
resource_id = params[:resource_id]
relationship_type = params[:relationship_type].to_sym
data = params.fetch(:data)
Expand All @@ -298,15 +298,21 @@ def replace_to_many_relationship
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
end

def remove_to_many_relationship
def remove_to_many_relationships
resource_id = params[:resource_id]
relationship_type = params[:relationship_type].to_sym
associated_key = params[:associated_key]
associated_keys = params[:associated_keys]

resource = resource_klass.find_by_key(resource_id, context: context)
result = resource.remove_to_many_link(relationship_type, associated_key)

return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
complete = true
associated_keys.each do |key|
result = resource.remove_to_many_link(relationship_type, key)
if complete && result != :completed
complete = false
end
end
return JSONAPI::OperationResult.new(complete ? :no_content : :accepted)
end

def remove_to_one_relationship
Expand Down
73 changes: 25 additions & 48 deletions lib/jsonapi/request_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -346,19 +346,19 @@ def add_show_related_resources_operation(relationship_type)
)
end

def parse_add_operation(data)
Array.wrap(data).each do |params|
verify_type(params[:type])
def parse_add_operation(params)
fail JSONAPI::Exceptions::InvalidDataFormat unless params.respond_to?(:each_pair)

data = parse_params(params, @resource_klass.creatable_fields(@context))
@operations.push JSONAPI::Operation.new(:create_resource,
@resource_klass,
context: @context,
data: data,
fields: @fields,
include_directives: @include_directives
)
end
verify_type(params[:type])

data = parse_params(params, @resource_klass.creatable_fields(@context))
@operations.push JSONAPI::Operation.new(:create_resource,
@resource_klass,
context: @context,
data: data,
fields: @fields,
include_directives: @include_directives
)
rescue JSONAPI::Exceptions::Error => e
@errors.concat(e.errors)
end
Expand Down Expand Up @@ -558,7 +558,7 @@ def verify_permitted_params(params, allowed_fields)

def parse_add_relationship_operation(verified_params, relationship, parent_key)
if relationship.is_a?(JSONAPI::Relationship::ToMany)
@operations.push JSONAPI::Operation.new(:create_to_many_relationship,
@operations.push JSONAPI::Operation.new(:create_to_many_relationships,
resource_klass,
context: @context,
resource_id: parent_key,
Expand Down Expand Up @@ -590,13 +590,15 @@ def parse_update_relationship_operation(verified_params, relationship, parent_ke
fail JSONAPI::Exceptions::ToManySetReplacementForbidden.new
end
options[:data] = verified_params[:to_many].values[0]
operation_type = :replace_to_many_relationship
operation_type = :replace_to_many_relationships
end

@operations.push JSONAPI::Operation.new(operation_type, resource_klass, options)
end

def parse_single_replace_operation(data, keys, id_key_presence_check_required: true)
fail JSONAPI::Exceptions::InvalidDataFormat unless data.respond_to?(:each_pair)

fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?

key = data[:id].to_s
Expand All @@ -619,31 +621,16 @@ def parse_single_replace_operation(data, keys, id_key_presence_check_required: t
end

def parse_replace_operation(data, keys)
if data.is_a?(Array)
fail JSONAPI::Exceptions::CountMismatch if keys.count != data.count

data.each do |object_params|
parse_single_replace_operation(object_params, keys)
end
else
parse_single_replace_operation(data, [keys],
id_key_presence_check_required: keys.present?)
end

parse_single_replace_operation(data, [keys], id_key_presence_check_required: keys.present?)
rescue JSONAPI::Exceptions::Error => e
@errors.concat(e.errors)
end

def parse_remove_operation(params)
keys = parse_key_array(params.require(:id))

keys.each do |key|
@operations.push JSONAPI::Operation.new(:remove_resource,
@resource_klass,
context: @context,
resource_id: key
)
end
@operations.push JSONAPI::Operation.new(:remove_resource,
@resource_klass,
context: @context,
resource_id: @resource_klass.verify_key(params.require(:id), context))
rescue JSONAPI::Exceptions::Error => e
@errors.concat(e.errors)
end
Expand All @@ -656,25 +643,15 @@ def parse_remove_relationship_operation(params, relationship, parent_key)
)

if relationship.is_a?(JSONAPI::Relationship::ToMany)
operation_args = operation_base_args.dup
keys = params[:to_many].values[0]
keys.each do |key|
operation_args = operation_base_args.dup
operation_args[1] = operation_args[1].merge(associated_key: key)
@operations.push JSONAPI::Operation.new(:remove_to_many_relationship,
*operation_args
)
end
operation_args[1] = operation_args[1].merge(associated_keys: keys)
@operations.push JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
else
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship,
*operation_base_args
)
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
end
end

def parse_key_array(raw)
@resource_klass.verify_keys(raw.split(/,/), context)
end

def format_key(key)
@key_formatter.format(key)
end
Expand Down
6 changes: 3 additions & 3 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ en:
invalid_field_format:
title: 'Invalid field format'
detail: 'Fields must specify a type.'
invalid_data_format:
title: 'Invalid data format'
detail: 'Data must be a hash.'
invalid_links_object:
title: 'Invalid Links Object'
detail: 'Data is not a valid Links Object.'
Expand All @@ -58,9 +61,6 @@ en:
parameter_missing:
title: 'Missing Parameter'
detail: "The required parameter, %{param}, is missing."
count_mismatch:
title: 'Count to key mismatch'
detail: 'The resource collection does not contain the same number of objects as the number of keys.'
key_not_included_in_url:
title: 'Key is not included in URL'
detail: "The URL does not support the key %{key}"
Expand Down
Loading