simple_jsonapi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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