Skip to content

Commit a6d2098

Browse files
authored
Merge pull request #1 from jsonapi-rb/separate-error-renderer
Decouple errors from success documents.
2 parents c62ba8f + ed2dc66 commit a6d2098

3 files changed

Lines changed: 114 additions & 87 deletions

File tree

lib/jsonapi/renderer.rb

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,90 +1,7 @@
1-
require 'jsonapi/include_directive'
1+
require 'jsonapi/renderer/error_document'
2+
require 'jsonapi/renderer/success_document'
23

34
module JSONAPI
4-
class Renderer
5-
def initialize(resources, options = {})
6-
@resources = resources
7-
@errors = options[:errors] || false
8-
@meta = options[:meta] || nil
9-
@links = options[:links] || {}
10-
@fields = options[:fields] || {}
11-
# NOTE(beauby): Room for some nifty defaults on those.
12-
@jsonapi = options[:jsonapi_object] || nil
13-
@include = JSONAPI::IncludeDirective.new(options[:include] || {})
14-
end
15-
16-
def as_json
17-
return @json unless @json.nil?
18-
19-
process_resources
20-
@json = {}
21-
22-
if @errors
23-
@json[:errors] = @resources.map(&:as_jsonapi)
24-
else
25-
@json[:data] = @resources.respond_to?(:each) ? @primary : @primary[0]
26-
@json[:included] = @included if @included.any?
27-
end
28-
@json[:links] = @links if @links.any?
29-
@json[:meta] = @meta unless @meta.nil?
30-
@json[:jsonapi] = @jsonapi unless @jsonapi.nil?
31-
32-
@json
33-
end
34-
35-
private
36-
37-
def process_resources
38-
@primary = []
39-
@included = []
40-
@hashes = {}
41-
@processed = Set.new # NOTE(beauby): Set of [type, id, prefix].
42-
@queue = []
43-
44-
Array(@resources).each do |res|
45-
process_resource(res, '', @include, true)
46-
@processed.add([res.jsonapi_type, res.jsonapi_id, ''])
47-
end
48-
until @queue.empty?
49-
res, prefix, include_dir = @queue.pop
50-
process_resource(res, prefix, include_dir, false)
51-
end
52-
end
53-
54-
def merge_resources!(a, b)
55-
b[:relationships].each do |name, rel|
56-
a[:relationships][name][:data] ||= rel[:data] if rel.key?(:data)
57-
(a[:relationships][name][:links] ||= {})
58-
.merge!(rel[:links]) if rel.key?(:links)
59-
end
60-
end
61-
62-
def process_resource(res, prefix, include_dir, is_primary)
63-
ri = [res.jsonapi_type, res.jsonapi_id]
64-
hash = res.as_jsonapi(fields: @fields[res.jsonapi_type.to_sym],
65-
include: include_dir.keys)
66-
if @hashes.key?(ri)
67-
merge_resources!(@hashes[ri], hash)
68-
else
69-
(is_primary ? @primary : @included) << (@hashes[ri] = hash)
70-
end
71-
process_relationships(res, prefix, include_dir)
72-
end
73-
74-
def process_relationships(res, prefix, include_dir)
75-
res.jsonapi_related(include_dir.keys).each do |key, data|
76-
Array(data).each do |child_res|
77-
next if child_res.nil?
78-
child_prefix = "#{prefix}.#{key}"
79-
next unless @processed.add?([child_res.jsonapi_type,
80-
child_res.jsonapi_id,
81-
child_prefix])
82-
@queue << [child_res, child_prefix, include_dir[key]]
83-
end
84-
end
85-
end
86-
end
87-
885
module_function
896

907
# Render a success JSON API document.
@@ -102,7 +19,7 @@ def process_relationships(res, prefix, include_dir)
10219
# @option [Hash] links Top-level links to be included.
10320
# @option [Hash] jsonapi_object JSON API object.
10421
def render(resources, options = {})
105-
Renderer.new(resources, options).as_json
22+
Renderer::SuccessDocument.new(resources, options).as_json
10623
end
10724

10825
# Render an error JSON API document.
@@ -114,6 +31,6 @@ def render(resources, options = {})
11431
# @option [Hash] links Top-level links to be included.
11532
# @option [Hash] jsonapi_object JSON API object.
11633
def render_errors(errors)
117-
Renderer.new(errors, errors: true).as_json
34+
Renderer::ErrorDocument.new(errors).as_json
11835
end
11936
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module JSONAPI
2+
module Renderer
3+
class ErrorRenderer
4+
def initialize(errors, options = {})
5+
@errors = errors
6+
@meta = options[:meta] || nil
7+
@links = options[:links] || {}
8+
@jsonapi = options[:jsonapi_object] || nil
9+
end
10+
11+
def as_json
12+
return @json unless @json.nil?
13+
14+
@json = {}
15+
@json[:errors] = @resources.map(&:as_jsonapi)
16+
@json[:links] = @links if @links.any?
17+
@json[:meta] = @meta unless @meta.nil?
18+
@json[:jsonapi] = @jsonapi unless @jsonapi.nil?
19+
20+
@json
21+
end
22+
end
23+
end
24+
end
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
require 'set'
2+
3+
require 'jsonapi/include_directive'
4+
5+
module JSONAPI
6+
module Renderer
7+
class SuccessDocument
8+
def initialize(resources, options = {})
9+
@resources = resources
10+
@meta = options[:meta] || nil
11+
@links = options[:links] || {}
12+
@fields = options[:fields] || {}
13+
# NOTE(beauby): Room for some nifty defaults on those.
14+
@jsonapi = options[:jsonapi_object] || nil
15+
@include = JSONAPI::IncludeDirective.new(options[:include] || {})
16+
end
17+
18+
def as_json
19+
return @json unless @json.nil?
20+
21+
process_resources
22+
23+
@json = {}
24+
@json[:data] = @resources.respond_to?(:each) ? @primary : @primary[0]
25+
@json[:included] = @included if @included.any?
26+
@json[:links] = @links if @links.any?
27+
@json[:meta] = @meta unless @meta.nil?
28+
@json[:jsonapi] = @jsonapi unless @jsonapi.nil?
29+
30+
@json
31+
end
32+
33+
private
34+
35+
def process_resources
36+
@primary = []
37+
@included = []
38+
@hashes = {}
39+
@processed = Set.new # NOTE(beauby): Set of [type, id, prefix].
40+
@queue = []
41+
42+
Array(@resources).each do |res|
43+
process_resource(res, '', @include, true)
44+
@processed.add([res.jsonapi_type, res.jsonapi_id, ''])
45+
end
46+
until @queue.empty?
47+
res, prefix, include_dir = @queue.pop
48+
process_resource(res, prefix, include_dir, false)
49+
end
50+
end
51+
52+
def merge_resources!(a, b)
53+
b[:relationships].each do |name, rel|
54+
a[:relationships][name][:data] ||= rel[:data] if rel.key?(:data)
55+
(a[:relationships][name][:links] ||= {})
56+
.merge!(rel[:links]) if rel.key?(:links)
57+
end
58+
end
59+
60+
def process_resource(res, prefix, include_dir, is_primary)
61+
ri = [res.jsonapi_type, res.jsonapi_id]
62+
hash = res.as_jsonapi(fields: @fields[res.jsonapi_type.to_sym],
63+
include: include_dir.keys)
64+
if @hashes.key?(ri)
65+
merge_resources!(@hashes[ri], hash)
66+
else
67+
(is_primary ? @primary : @included) << (@hashes[ri] = hash)
68+
end
69+
process_relationships(res, prefix, include_dir)
70+
end
71+
72+
def process_relationships(res, prefix, include_dir)
73+
res.jsonapi_related(include_dir.keys).each do |key, data|
74+
Array(data).each do |child_res|
75+
next if child_res.nil?
76+
child_prefix = "#{prefix}.#{key}"
77+
next unless @processed.add?([child_res.jsonapi_type,
78+
child_res.jsonapi_id,
79+
child_prefix])
80+
@queue << [child_res, child_prefix, include_dir[key]]
81+
end
82+
end
83+
end
84+
end
85+
end
86+
end

0 commit comments

Comments
 (0)