Skip to content

Commit e30c43d

Browse files
authored
Merge pull request cerebris#845 from lgebhardt/base_spec_single_ops
Handle all base spec requests as a single operation
2 parents 0534288 + 78e3560 commit e30c43d

File tree

8 files changed

+116
-259
lines changed

8 files changed

+116
-259
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: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ class Processor
1111
:replace_fields,
1212
:replace_to_one_relationship,
1313
:replace_polymorphic_to_one_relationship,
14-
:create_to_many_relationship,
15-
:replace_to_many_relationship,
16-
:remove_to_many_relationship,
14+
:create_to_many_relationships,
15+
:replace_to_many_relationships,
16+
:remove_to_many_relationships,
1717
:remove_to_one_relationship,
1818
:operation
1919

@@ -276,7 +276,7 @@ def replace_polymorphic_to_one_relationship
276276
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
277277
end
278278

279-
def create_to_many_relationship
279+
def create_to_many_relationships
280280
resource_id = params[:resource_id]
281281
relationship_type = params[:relationship_type].to_sym
282282
data = params[:data]
@@ -287,7 +287,7 @@ def create_to_many_relationship
287287
return JSONAPI::OperationResult.new(result == :completed ? :no_content : :accepted)
288288
end
289289

290-
def replace_to_many_relationship
290+
def replace_to_many_relationships
291291
resource_id = params[:resource_id]
292292
relationship_type = params[:relationship_type].to_sym
293293
data = params.fetch(:data)
@@ -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: 25 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -346,19 +346,19 @@ def add_show_related_resources_operation(relationship_type)
346346
)
347347
end
348348

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

353-
data = parse_params(params, @resource_klass.creatable_fields(@context))
354-
@operations.push JSONAPI::Operation.new(:create_resource,
355-
@resource_klass,
356-
context: @context,
357-
data: data,
358-
fields: @fields,
359-
include_directives: @include_directives
360-
)
361-
end
352+
verify_type(params[:type])
353+
354+
data = parse_params(params, @resource_klass.creatable_fields(@context))
355+
@operations.push JSONAPI::Operation.new(:create_resource,
356+
@resource_klass,
357+
context: @context,
358+
data: data,
359+
fields: @fields,
360+
include_directives: @include_directives
361+
)
362362
rescue JSONAPI::Exceptions::Error => e
363363
@errors.concat(e.errors)
364364
end
@@ -558,7 +558,7 @@ def verify_permitted_params(params, allowed_fields)
558558

559559
def parse_add_relationship_operation(verified_params, relationship, parent_key)
560560
if relationship.is_a?(JSONAPI::Relationship::ToMany)
561-
@operations.push JSONAPI::Operation.new(:create_to_many_relationship,
561+
@operations.push JSONAPI::Operation.new(:create_to_many_relationships,
562562
resource_klass,
563563
context: @context,
564564
resource_id: parent_key,
@@ -590,13 +590,15 @@ def parse_update_relationship_operation(verified_params, relationship, parent_ke
590590
fail JSONAPI::Exceptions::ToManySetReplacementForbidden.new
591591
end
592592
options[:data] = verified_params[:to_many].values[0]
593-
operation_type = :replace_to_many_relationship
593+
operation_type = :replace_to_many_relationships
594594
end
595595

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

599599
def parse_single_replace_operation(data, keys, id_key_presence_check_required: true)
600+
fail JSONAPI::Exceptions::InvalidDataFormat unless data.respond_to?(:each_pair)
601+
600602
fail JSONAPI::Exceptions::MissingKey.new if data[:id].nil?
601603

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

621623
def parse_replace_operation(data, keys)
622-
if data.is_a?(Array)
623-
fail JSONAPI::Exceptions::CountMismatch if keys.count != data.count
624-
625-
data.each do |object_params|
626-
parse_single_replace_operation(object_params, keys)
627-
end
628-
else
629-
parse_single_replace_operation(data, [keys],
630-
id_key_presence_check_required: keys.present?)
631-
end
632-
624+
parse_single_replace_operation(data, [keys], id_key_presence_check_required: keys.present?)
633625
rescue JSONAPI::Exceptions::Error => e
634626
@errors.concat(e.errors)
635627
end
636628

637629
def parse_remove_operation(params)
638-
keys = parse_key_array(params.require(:id))
639-
640-
keys.each do |key|
641-
@operations.push JSONAPI::Operation.new(:remove_resource,
642-
@resource_klass,
643-
context: @context,
644-
resource_id: key
645-
)
646-
end
630+
@operations.push JSONAPI::Operation.new(:remove_resource,
631+
@resource_klass,
632+
context: @context,
633+
resource_id: @resource_klass.verify_key(params.require(:id), context))
647634
rescue JSONAPI::Exceptions::Error => e
648635
@errors.concat(e.errors)
649636
end
@@ -656,25 +643,15 @@ def parse_remove_relationship_operation(params, relationship, parent_key)
656643
)
657644

658645
if relationship.is_a?(JSONAPI::Relationship::ToMany)
646+
operation_args = operation_base_args.dup
659647
keys = params[:to_many].values[0]
660-
keys.each do |key|
661-
operation_args = operation_base_args.dup
662-
operation_args[1] = operation_args[1].merge(associated_key: key)
663-
@operations.push JSONAPI::Operation.new(:remove_to_many_relationship,
664-
*operation_args
665-
)
666-
end
648+
operation_args[1] = operation_args[1].merge(associated_keys: keys)
649+
@operations.push JSONAPI::Operation.new(:remove_to_many_relationships, *operation_args)
667650
else
668-
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship,
669-
*operation_base_args
670-
)
651+
@operations.push JSONAPI::Operation.new(:remove_to_one_relationship, *operation_base_args)
671652
end
672653
end
673654

674-
def parse_key_array(raw)
675-
@resource_klass.verify_keys(raw.split(/,/), context)
676-
end
677-
678655
def format_key(key)
679656
@key_formatter.format(key)
680657
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)