Skip to content

Commit ff8b0c9

Browse files
committed
Handle all base spec requests as a single operation
Getting ready for multiple operation support in requests
1 parent e53a32d commit ff8b0c9

File tree

7 files changed

+106
-249
lines changed

7 files changed

+106
-249
lines changed

lib/jsonapi/error_codes.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ module JSONAPI
77
PARAM_NOT_ALLOWED = '105'
88
PARAM_MISSING = '106'
99
INVALID_FILTER_VALUE = '107'
10-
COUNT_MISMATCH = '108'
1110
KEY_ORDER_MISMATCH = '109'
1211
KEY_NOT_INCLUDED_IN_URL = '110'
1312
INVALID_INCLUDE = '112'
@@ -20,6 +19,7 @@ module JSONAPI
2019
INVALID_FIELD_FORMAT = '119'
2120
INVALID_FILTERS_SYNTAX = '120'
2221
SAVE_FAILED = '121'
22+
INVALID_DATA_FORMAT = '122'
2323
FORBIDDEN = '403'
2424
RECORD_NOT_FOUND = '404'
2525
NOT_ACCEPTABLE = '406'
@@ -36,7 +36,6 @@ module JSONAPI
3636
PARAM_NOT_ALLOWED => 'PARAM_NOT_ALLOWED',
3737
PARAM_MISSING => 'PARAM_MISSING',
3838
INVALID_FILTER_VALUE => 'INVALID_FILTER_VALUE',
39-
COUNT_MISMATCH => 'COUNT_MISMATCH',
4039
KEY_ORDER_MISMATCH => 'KEY_ORDER_MISMATCH',
4140
KEY_NOT_INCLUDED_IN_URL => 'KEY_NOT_INCLUDED_IN_URL',
4241
INVALID_INCLUDE => 'INVALID_INCLUDE',
@@ -49,6 +48,7 @@ module JSONAPI
4948
INVALID_FIELD_FORMAT => 'INVALID_FIELD_FORMAT',
5049
INVALID_FILTERS_SYNTAX => 'INVALID_FILTERS_SYNTAX',
5150
SAVE_FAILED => 'SAVE_FAILED',
51+
INVALID_DATA_FORMAT => 'INVALID_DATA_FORMAT',
5252
FORBIDDEN => 'FORBIDDEN',
5353
RECORD_NOT_FOUND => 'RECORD_NOT_FOUND',
5454
NOT_ACCEPTABLE => 'NOT_ACCEPTABLE',

lib/jsonapi/exceptions.rb

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ module JSONAPI
22
module Exceptions
33
class Error < RuntimeError
44
def errors
5+
# :nocov:
56
raise NotImplementedError, "Subclass of Error must implement errors method"
7+
# :nocov:
68
end
79
end
810

@@ -208,6 +210,17 @@ def errors
208210
end
209211
end
210212

213+
class InvalidDataFormat < Error
214+
def errors
215+
[JSONAPI::Error.new(code: JSONAPI::INVALID_DATA_FORMAT,
216+
status: :bad_request,
217+
title: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.title',
218+
default: 'Invalid data format'),
219+
detail: I18n.translate('jsonapi-resources.exceptions.invalid_data_format.detail',
220+
default: 'Data must be a hash.'))]
221+
end
222+
end
223+
211224
class InvalidLinksObject < Error
212225
def errors
213226
[JSONAPI::Error.new(code: JSONAPI::INVALID_LINKS_OBJECT,
@@ -324,17 +337,6 @@ def errors
324337
end
325338
end
326339

327-
class CountMismatch < Error
328-
def errors
329-
[JSONAPI::Error.new(code: JSONAPI::COUNT_MISMATCH,
330-
status: :bad_request,
331-
title: I18n.translate('jsonapi-resources.exceptions.count_mismatch.title',
332-
default: 'Count to key mismatch'),
333-
detail: I18n.translate('jsonapi-resources.exceptions.count_mismatch.detail',
334-
default: 'The resource collection does not contain the same number of objects as the number of keys.'))]
335-
end
336-
end
337-
338340
class KeyNotIncludedInURL < Error
339341
attr_accessor :key
340342
def initialize(key)

lib/jsonapi/processor.rb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Processor
1313
:replace_polymorphic_to_one_relationship,
1414
:create_to_many_relationship,
1515
:replace_to_many_relationship,
16-
:remove_to_many_relationship,
16+
:remove_to_many_relationships,
1717
:remove_to_one_relationship,
1818
:operation
1919

@@ -298,15 +298,21 @@ def replace_to_many_relationship
298298
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
299299
end
300300

301-
def remove_to_many_relationship
301+
def remove_to_many_relationships
302302
resource_id = params[:resource_id]
303303
relationship_type = params[:relationship_type].to_sym
304-
associated_key = params[:associated_key]
304+
associated_keys = params[:associated_keys]
305305

306306
resource = resource_klass.find_by_key(resource_id, context: context)
307-
result = resource.remove_to_many_link(relationship_type, associated_key)
308307

309-
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
308+
complete = true
309+
associated_keys.each do |key|
310+
result = resource.remove_to_many_link(relationship_type, key)
311+
if complete && result != :completed
312+
complete = false
313+
end
314+
end
315+
return JSONAPI::OperationResult.new(complete ? :no_content : :accepted)
310316
end
311317

312318
def remove_to_one_relationship

lib/jsonapi/request_parser.rb

Lines changed: 23 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -357,19 +357,19 @@ def creatable_fields
357357
end
358358
# :nocov:
359359

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

364-
data = parse_params(params, creatable_fields)
365-
@operations.push JSONAPI::Operation.new(:create_resource,
366-
@resource_klass,
367-
context: @context,
368-
data: data,
369-
fields: @fields,
370-
include_directives: @include_directives
371-
)
372-
end
363+
verify_type(params[:type])
364+
365+
data = parse_params(params, creatable_fields)
366+
@operations.push JSONAPI::Operation.new(:create_resource,
367+
@resource_klass,
368+
context: @context,
369+
data: data,
370+
fields: @fields,
371+
include_directives: @include_directives
372+
)
373373
rescue JSONAPI::Exceptions::Error => e
374374
@errors.concat(e.errors)
375375
end
@@ -619,6 +619,8 @@ def parse_update_relationship_operation(verified_params, relationship, parent_ke
619619
end
620620

621621
def parse_single_replace_operation(data, keys, id_key_presence_check_required: true)
622+
fail JSONAPI::Exceptions::InvalidDataFormat unless data.respond_to?(:each_pair)
623+
622624
fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?
623625

624626
key = data[:id].to_s
@@ -641,31 +643,16 @@ def parse_single_replace_operation(data, keys, id_key_presence_check_required: t
641643
end
642644

643645
def parse_replace_operation(data, keys)
644-
if data.is_a?(Array)
645-
fail JSONAPI::Exceptions::CountMismatch if keys.count != data.count
646-
647-
data.each do |object_params|
648-
parse_single_replace_operation(object_params, keys)
649-
end
650-
else
651-
parse_single_replace_operation(data, [keys],
652-
id_key_presence_check_required: keys.present?)
653-
end
654-
646+
parse_single_replace_operation(data, [keys], id_key_presence_check_required: keys.present?)
655647
rescue JSONAPI::Exceptions::Error => e
656648
@errors.concat(e.errors)
657649
end
658650

659651
def parse_remove_operation(params)
660-
keys = parse_key_array(params.require(:id))
661-
662-
keys.each do |key|
663-
@operations.push JSONAPI::Operation.new(:remove_resource,
664-
@resource_klass,
665-
context: @context,
666-
resource_id: key
667-
)
668-
end
652+
@operations.push JSONAPI::Operation.new(:remove_resource,
653+
@resource_klass,
654+
context: @context,
655+
resource_id: @resource_klass.verify_key(params.require(:id), context))
669656
rescue JSONAPI::Exceptions::Error => e
670657
@errors.concat(e.errors)
671658
end
@@ -678,25 +665,15 @@ def parse_remove_relationship_operation(params, relationship, parent_key)
678665
)
679666

680667
if relationship.is_a?(JSONAPI::Relationship::ToMany)
668+
operation_args = operation_base_args.dup
681669
keys = params[:to_many].values[0]
682-
keys.each do |key|
683-
operation_args = operation_base_args.dup
684-
operation_args[1] = operation_args[1].merge(associated_key: key)
685-
@operations.push JSONAPI::Operation.new(:remove_to_many_relationship,
686-
*operation_args
687-
)
688-
end
670+
operation_args[1] = operation_args[1].merge(associated_keys: keys)
671+
@operations.push JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
689672
else
690-
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship,
691-
*operation_base_args
692-
)
673+
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
693674
end
694675
end
695676

696-
def parse_key_array(raw)
697-
@resource_klass.verify_keys(raw.split(/,/), context)
698-
end
699-
700677
def format_key(key)
701678
@key_formatter.format(key)
702679
end

locales/en.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ en:
3737
invalid_field_format:
3838
title: 'Invalid field format'
3939
detail: 'Fields must specify a type.'
40+
invalid_data_format:
41+
title: 'Invalid data format'
42+
detail: 'Data must be a hash.'
4043
invalid_links_object:
4144
title: 'Invalid Links Object'
4245
detail: 'Data is not a valid Links Object.'
@@ -58,9 +61,6 @@ en:
5861
parameter_missing:
5962
title: 'Missing Parameter'
6063
detail: "The required parameter, %{param}, is missing."
61-
count_mismatch:
62-
title: 'Count to key mismatch'
63-
detail: 'The resource collection does not contain the same number of objects as the number of keys.'
6464
key_not_included_in_url:
6565
title: 'Key is not included in URL'
6666
detail: "The URL does not support the key %{key}"

0 commit comments

Comments
 (0)