simple_jsonapi 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +131 -0
  4. data/CHANGELOG.md +2 -0
  5. data/Gemfile +5 -0
  6. data/Jenkinsfile +92 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +532 -0
  9. data/Rakefile +10 -0
  10. data/lib/simple_jsonapi.rb +112 -0
  11. data/lib/simple_jsonapi/definition/attribute.rb +45 -0
  12. data/lib/simple_jsonapi/definition/base.rb +50 -0
  13. data/lib/simple_jsonapi/definition/concerns/has_links_object.rb +36 -0
  14. data/lib/simple_jsonapi/definition/concerns/has_meta_object.rb +36 -0
  15. data/lib/simple_jsonapi/definition/error.rb +70 -0
  16. data/lib/simple_jsonapi/definition/error_source.rb +29 -0
  17. data/lib/simple_jsonapi/definition/link.rb +27 -0
  18. data/lib/simple_jsonapi/definition/meta.rb +27 -0
  19. data/lib/simple_jsonapi/definition/relationship.rb +60 -0
  20. data/lib/simple_jsonapi/definition/resource.rb +104 -0
  21. data/lib/simple_jsonapi/error_serializer.rb +76 -0
  22. data/lib/simple_jsonapi/errors/bad_request.rb +11 -0
  23. data/lib/simple_jsonapi/errors/exception_serializer.rb +6 -0
  24. data/lib/simple_jsonapi/errors/wrapped_error.rb +35 -0
  25. data/lib/simple_jsonapi/errors/wrapped_error_serializer.rb +35 -0
  26. data/lib/simple_jsonapi/helpers/exceptions.rb +39 -0
  27. data/lib/simple_jsonapi/helpers/serializer_inferrer.rb +136 -0
  28. data/lib/simple_jsonapi/helpers/serializer_methods.rb +36 -0
  29. data/lib/simple_jsonapi/node/attributes.rb +51 -0
  30. data/lib/simple_jsonapi/node/base.rb +91 -0
  31. data/lib/simple_jsonapi/node/data/collection.rb +25 -0
  32. data/lib/simple_jsonapi/node/data/singular.rb +26 -0
  33. data/lib/simple_jsonapi/node/document/base.rb +62 -0
  34. data/lib/simple_jsonapi/node/document/collection.rb +17 -0
  35. data/lib/simple_jsonapi/node/document/errors.rb +17 -0
  36. data/lib/simple_jsonapi/node/document/singular.rb +17 -0
  37. data/lib/simple_jsonapi/node/error.rb +55 -0
  38. data/lib/simple_jsonapi/node/error_source.rb +40 -0
  39. data/lib/simple_jsonapi/node/errors.rb +28 -0
  40. data/lib/simple_jsonapi/node/included.rb +45 -0
  41. data/lib/simple_jsonapi/node/object_links.rb +40 -0
  42. data/lib/simple_jsonapi/node/object_meta.rb +40 -0
  43. data/lib/simple_jsonapi/node/relationship.rb +79 -0
  44. data/lib/simple_jsonapi/node/relationship_data/base.rb +53 -0
  45. data/lib/simple_jsonapi/node/relationship_data/collection.rb +32 -0
  46. data/lib/simple_jsonapi/node/relationship_data/singular.rb +33 -0
  47. data/lib/simple_jsonapi/node/relationships.rb +60 -0
  48. data/lib/simple_jsonapi/node/resource/base.rb +21 -0
  49. data/lib/simple_jsonapi/node/resource/full.rb +49 -0
  50. data/lib/simple_jsonapi/node/resource/linkage.rb +25 -0
  51. data/lib/simple_jsonapi/parameters/fields_spec.rb +45 -0
  52. data/lib/simple_jsonapi/parameters/include_spec.rb +57 -0
  53. data/lib/simple_jsonapi/parameters/sort_spec.rb +107 -0
  54. data/lib/simple_jsonapi/serializer.rb +89 -0
  55. data/lib/simple_jsonapi/version.rb +3 -0
  56. data/simple_jsonapi.gemspec +29 -0
  57. data/test/errors/bad_request_test.rb +34 -0
  58. data/test/errors/error_serializer_test.rb +229 -0
  59. data/test/errors/exception_serializer_test.rb +25 -0
  60. data/test/errors/wrapped_error_serializer_test.rb +91 -0
  61. data/test/errors/wrapped_error_test.rb +44 -0
  62. data/test/parameters/fields_spec_test.rb +56 -0
  63. data/test/parameters/include_spec_test.rb +58 -0
  64. data/test/parameters/sort_spec_test.rb +65 -0
  65. data/test/resources/attributes_test.rb +109 -0
  66. data/test/resources/extras_test.rb +70 -0
  67. data/test/resources/id_and_type_test.rb +76 -0
  68. data/test/resources/inclusion_test.rb +134 -0
  69. data/test/resources/links_test.rb +63 -0
  70. data/test/resources/meta_test.rb +49 -0
  71. data/test/resources/relationships_test.rb +262 -0
  72. data/test/resources/sorting_test.rb +79 -0
  73. data/test/resources/sparse_fieldset_test.rb +160 -0
  74. data/test/root_objects_test.rb +165 -0
  75. data/test/test_helper.rb +31 -0
  76. metadata +235 -0
@@ -0,0 +1,229 @@
1
+ require 'test_helper'
2
+
3
+ class ErrorSerializerTest < Minitest::Spec
4
+ class Problem < TestModel
5
+ attr_accessor :id, :name, :number, :date
6
+ end
7
+
8
+ class DefaultsSerializer < SimpleJsonapi::ErrorSerializer
9
+ end
10
+
11
+ class BlocksSerializer < SimpleJsonapi::ErrorSerializer
12
+ id(&:id)
13
+ status { "422" }
14
+ code(&:number)
15
+ title(&:name)
16
+ detail { |err| "#{err.name} #{err.number}" }
17
+ source do
18
+ pointer { |err| "/to/#{err.name}" }
19
+ parameter { |err| err.class.name }
20
+ end
21
+ about_link { |err| "https://www.patientslikeme.com/error/#{err.id}" }
22
+ meta(:date) { |err| err.date&.iso8601 }
23
+ end
24
+
25
+ class ProcsSerializer < SimpleJsonapi::ErrorSerializer
26
+ id ->(err) { err.id }
27
+ status ->(_err) { "422" }
28
+ code ->(err) { err.number }
29
+ title ->(err) { err.name }
30
+ detail ->(err) { "#{err.name} #{err.number}" }
31
+ source do
32
+ pointer ->(err) { "/to/#{err.name}" }
33
+ parameter ->(err) { err.class.name }
34
+ end
35
+ about_link ->(err) { "https://www.patientslikeme.com/error/#{err.id}" }
36
+ meta :date, ->(err) { err.date&.iso8601 }
37
+ end
38
+
39
+ class ValuesSerializer < SimpleJsonapi::ErrorSerializer
40
+ id "42"
41
+ status "422"
42
+ code "the_code"
43
+ title "the title"
44
+ detail "the details"
45
+ source do
46
+ pointer "/to/somewhere"
47
+ parameter "the_parameter"
48
+ end
49
+ about_link "https://www.patientslikeme.com/errors"
50
+ meta :date, "2017-01-01"
51
+ end
52
+
53
+ let(:problem) { Problem.new(id: 12, name: "BadThing", number: "999", date: Date.new(2017, 7, 1)) }
54
+
55
+ let(:default_serialized) do
56
+ SimpleJsonapi.render_errors(problem, serializer: DefaultsSerializer)[:errors].first
57
+ end
58
+ let(:blocks_serialized) do
59
+ SimpleJsonapi.render_errors(problem, serializer: BlocksSerializer)[:errors].first
60
+ end
61
+ let(:procs_serialized) do
62
+ SimpleJsonapi.render_errors(problem, serializer: ProcsSerializer)[:errors].first
63
+ end
64
+ let(:values_serialized) do
65
+ SimpleJsonapi.render_errors(problem, serializer: ValuesSerializer)[:errors].first
66
+ end
67
+
68
+ describe SimpleJsonapi::ErrorSerializer do
69
+ describe "id property" do
70
+ it "is excluded by default" do
71
+ refute default_serialized.key?(:id)
72
+ end
73
+
74
+ it "accepts a block" do
75
+ assert_equal "12", blocks_serialized[:id]
76
+ end
77
+
78
+ it "accepts a proc" do
79
+ assert_equal "12", procs_serialized[:id]
80
+ end
81
+
82
+ it "accepts a value" do
83
+ assert_equal "42", values_serialized[:id]
84
+ end
85
+ end
86
+
87
+ describe "status property" do
88
+ it "is excluded by default" do
89
+ refute default_serialized.key?(:status)
90
+ end
91
+
92
+ it "accepts a block" do
93
+ assert_equal "422", blocks_serialized[:status]
94
+ end
95
+
96
+ it "accepts a proc" do
97
+ assert_equal "422", procs_serialized[:status]
98
+ end
99
+
100
+ it "accepts a value" do
101
+ assert_equal "422", values_serialized[:status]
102
+ end
103
+ end
104
+
105
+ describe "code property" do
106
+ it "is excluded by default" do
107
+ refute default_serialized.key?(:code)
108
+ end
109
+
110
+ it "accepts a block" do
111
+ assert_equal "999", blocks_serialized[:code]
112
+ end
113
+
114
+ it "accepts a proc" do
115
+ assert_equal "999", procs_serialized[:code]
116
+ end
117
+
118
+ it "accepts a value" do
119
+ assert_equal "the_code", values_serialized[:code]
120
+ end
121
+ end
122
+
123
+ describe "title property" do
124
+ it "is excluded by default" do
125
+ refute default_serialized.key?(:title)
126
+ end
127
+
128
+ it "accepts a block" do
129
+ assert_equal "BadThing", blocks_serialized[:title]
130
+ end
131
+
132
+ it "accepts a proc" do
133
+ assert_equal "BadThing", procs_serialized[:title]
134
+ end
135
+
136
+ it "accepts a value" do
137
+ assert_equal "the title", values_serialized[:title]
138
+ end
139
+ end
140
+
141
+ describe "detail property" do
142
+ it "is excluded by default" do
143
+ refute default_serialized.key?(:detail)
144
+ end
145
+
146
+ it "accepts a block" do
147
+ assert_equal "BadThing 999", blocks_serialized[:detail]
148
+ end
149
+
150
+ it "accepts a proc" do
151
+ assert_equal "BadThing 999", procs_serialized[:detail]
152
+ end
153
+
154
+ it "accepts a value" do
155
+ assert_equal "the details", values_serialized[:detail]
156
+ end
157
+ end
158
+
159
+ describe "source object" do
160
+ it "is excluded by default" do
161
+ refute default_serialized.key?(:source)
162
+ end
163
+ end
164
+
165
+ describe "source pointer property" do
166
+ it "accepts a block" do
167
+ assert_equal "/to/BadThing", blocks_serialized.dig(:source, :pointer)
168
+ end
169
+
170
+ it "accepts a proc" do
171
+ assert_equal "/to/BadThing", procs_serialized.dig(:source, :pointer)
172
+ end
173
+
174
+ it "accepts a value" do
175
+ assert_equal "/to/somewhere", values_serialized.dig(:source, :pointer)
176
+ end
177
+ end
178
+
179
+ describe "source parameter property" do
180
+ it "accepts a block" do
181
+ assert_equal problem.class.name, blocks_serialized.dig(:source, :parameter)
182
+ end
183
+
184
+ it "accepts a proc" do
185
+ assert_equal problem.class.name, procs_serialized.dig(:source, :parameter)
186
+ end
187
+
188
+ it "accepts a value" do
189
+ assert_equal "the_parameter", values_serialized.dig(:source, :parameter)
190
+ end
191
+ end
192
+
193
+ describe "about link" do
194
+ it "is excluded by default" do
195
+ refute default_serialized.key?(:links)
196
+ end
197
+
198
+ it "accepts a block" do
199
+ assert_equal "https://www.patientslikeme.com/error/12", blocks_serialized.dig(:links, :about)
200
+ end
201
+
202
+ it "accepts a proc" do
203
+ assert_equal "https://www.patientslikeme.com/error/12", procs_serialized.dig(:links, :about)
204
+ end
205
+
206
+ it "accepts a value" do
207
+ assert_equal "https://www.patientslikeme.com/errors", values_serialized.dig(:links, :about)
208
+ end
209
+ end
210
+
211
+ describe "meta information" do
212
+ it "is excluded by default" do
213
+ refute default_serialized.key?(:meta)
214
+ end
215
+
216
+ it "accepts a block" do
217
+ assert_equal "2017-07-01", blocks_serialized.dig(:meta, :date)
218
+ end
219
+
220
+ it "accepts a proc" do
221
+ assert_equal "2017-07-01", procs_serialized.dig(:meta, :date)
222
+ end
223
+
224
+ it "accepts a value" do
225
+ assert_equal "2017-01-01", values_serialized.dig(:meta, :date)
226
+ end
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class ExceptionSerializerTest < Minitest::Spec
4
+ class SampleException < StandardError
5
+ end
6
+
7
+ let(:exception) { SampleException.new("the message") }
8
+ let(:serialized) do
9
+ SimpleJsonapi.render_errors(exception, serializer: SimpleJsonapi::Errors::ExceptionSerializer)[:errors].first
10
+ end
11
+
12
+ describe SimpleJsonapi::Errors::ExceptionSerializer do
13
+ it "sets code to the class name in snake case" do
14
+ assert_equal "exception_serializer_test_sample_exception", serialized[:code]
15
+ end
16
+
17
+ it "sets title to the class name" do
18
+ assert_equal "ExceptionSerializerTest::SampleException", serialized[:title]
19
+ end
20
+
21
+ it "sets detail to the message" do
22
+ assert_equal "the message", serialized[:detail]
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,91 @@
1
+ require 'test_helper'
2
+
3
+ class WrappedErrorSerializerTest < Minitest::Spec
4
+ let(:cause) { StandardError.new("the message") }
5
+
6
+ let(:wrapped) do
7
+ SimpleJsonapi::Errors::WrappedError.new(
8
+ cause,
9
+ id: "the id",
10
+ status: "the status",
11
+ code: "the code",
12
+ title: "the title",
13
+ detail: "the detail",
14
+ source_pointer: "the source pointer",
15
+ source_parameter: "the source parameter",
16
+ about_link: "the about link",
17
+ )
18
+ end
19
+
20
+ let(:serialized) do
21
+ rendered_errors = SimpleJsonapi.render_errors(
22
+ wrapped,
23
+ serializer: SimpleJsonapi::Errors::WrappedErrorSerializer,
24
+ )
25
+ rendered_errors[:errors].first
26
+ end
27
+
28
+ describe SimpleJsonapi::Errors::WrappedErrorSerializer do
29
+ it "outputs the id property" do
30
+ assert_equal "the id", serialized[:id]
31
+ end
32
+
33
+ it "outputs the status property" do
34
+ assert_equal "the status", serialized[:status]
35
+ end
36
+
37
+ it "outputs the code property" do
38
+ assert_equal "the code", serialized[:code]
39
+ end
40
+
41
+ it "outputs the title property" do
42
+ assert_equal "the title", serialized[:title]
43
+ end
44
+
45
+ it "outputs the detail property" do
46
+ assert_equal "the detail", serialized[:detail]
47
+ end
48
+
49
+ it "outputs the nested source pointer" do
50
+ assert_equal "the source pointer", serialized[:source][:pointer]
51
+ end
52
+
53
+ it "outputs the nested source parameter" do
54
+ assert_equal "the source parameter", serialized[:source][:parameter]
55
+ end
56
+
57
+ it "outputs an about link" do
58
+ assert_equal "the about link", serialized[:links][:about]
59
+ end
60
+
61
+ it "omits blank properties" do
62
+ blank_error = SimpleJsonapi::Errors::WrappedError.new(
63
+ cause,
64
+ id: " ",
65
+ status: " ",
66
+ code: " ",
67
+ title: " ",
68
+ detail: " ",
69
+ source_pointer: " ",
70
+ source_parameter: " ",
71
+ about_link: " ",
72
+ )
73
+
74
+ rendered_errors = SimpleJsonapi.render_errors(
75
+ blank_error, serializer:
76
+ SimpleJsonapi::Errors::WrappedErrorSerializer,
77
+ )
78
+
79
+ serialized_blank = rendered_errors[:errors].first
80
+
81
+ refute_includes serialized_blank.keys, :id
82
+ refute_includes serialized_blank.keys, :status
83
+ refute_includes serialized_blank.keys, :code
84
+ refute_includes serialized_blank.keys, :title
85
+ refute_includes serialized_blank.keys, :detail
86
+ refute_includes serialized_blank.keys, :source
87
+ refute_includes serialized_blank.keys, :source
88
+ refute_includes serialized_blank.keys, :links
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+
3
+ class WrappedErrorTest < Minitest::Spec
4
+ let(:cause) { StandardError.new("the message") }
5
+
6
+ let(:wrapped) do
7
+ SimpleJsonapi::Errors::WrappedError.new(
8
+ cause,
9
+ id: "the id",
10
+ status: "the status",
11
+ code: "the code",
12
+ title: "the title",
13
+ detail: "the detail",
14
+ source_pointer: "the source pointer",
15
+ source_parameter: "the source parameter",
16
+ about_link: "the about link",
17
+ )
18
+ end
19
+
20
+ describe SimpleJsonapi::Errors::WrappedError do
21
+ describe "cause" do
22
+ it "defaults to nil" do
23
+ assert_nil SimpleJsonapi::Errors::WrappedError.new.cause
24
+ end
25
+
26
+ it "is stored" do
27
+ assert_equal cause, wrapped.cause
28
+ end
29
+ end
30
+
31
+ describe "other properties" do
32
+ it "are stored" do
33
+ assert_equal "the id", wrapped.id
34
+ assert_equal "the status", wrapped.status
35
+ assert_equal "the code", wrapped.code
36
+ assert_equal "the title", wrapped.title
37
+ assert_equal "the detail", wrapped.detail
38
+ assert_equal "the source pointer", wrapped.source_pointer
39
+ assert_equal "the source parameter", wrapped.source_parameter
40
+ assert_equal "the about link", wrapped.about_link
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,56 @@
1
+ require 'test_helper'
2
+
3
+ class FieldsSpecTest < Minitest::Spec
4
+ describe SimpleJsonapi::Parameters::FieldsSpec do
5
+ describe "parsing" do
6
+ it "accepts comma-delimited strings" do
7
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new(
8
+ "orders" => "customer_name,description",
9
+ "line_items" => "order_id,product_id",
10
+ )
11
+
12
+ assert_equal [:customer_name, :description], spec[:orders]
13
+ assert_equal [:order_id, :product_id], spec[:line_items]
14
+ end
15
+
16
+ it "accepts arrays of strings" do
17
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new(
18
+ "orders" => ["customer_name", "description"],
19
+ "line_items" => ["order_id", "product_id"],
20
+ )
21
+
22
+ assert_equal [:customer_name, :description], spec[:orders]
23
+ assert_equal [:order_id, :product_id], spec[:line_items]
24
+ end
25
+
26
+ it "accepts arrays of symbols" do
27
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new(
28
+ orders: [:customer_name, :description],
29
+ line_items: [:order_id, :product_id],
30
+ )
31
+
32
+ assert_equal [:customer_name, :description], spec[:orders]
33
+ assert_equal [:order_id, :product_id], spec[:line_items]
34
+ end
35
+ end
36
+
37
+ describe "all_fields?" do
38
+ it "is true if nothing is defined for the type" do
39
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new
40
+ assert_equal true, spec.all_fields?(:orders)
41
+ end
42
+
43
+ it "is false if the type is assigned any fields" do
44
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new(
45
+ "orders" => "customer_name,description",
46
+ )
47
+ assert_equal false, spec.all_fields?(:orders)
48
+ end
49
+
50
+ it "is false if the type is assigned an empty list" do
51
+ spec = SimpleJsonapi::Parameters::FieldsSpec.new("orders" => "")
52
+ assert_equal false, spec.all_fields?(:orders)
53
+ end
54
+ end
55
+ end
56
+ end