infinum_json_api_setup 0.0.3

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 (115) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.overcommit.yml +26 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +29 -0
  6. data/.ruby-version +1 -0
  7. data/.simplecov +3 -0
  8. data/Gemfile +10 -0
  9. data/Gemfile.lock +268 -0
  10. data/README.md +156 -0
  11. data/Rakefile +1 -0
  12. data/bin/setup +18 -0
  13. data/infinum_json_api_setup.gemspec +30 -0
  14. data/lib/generators/infinum_json_api_setup/install_generator.rb +12 -0
  15. data/lib/generators/infinum_json_api_setup/templates/config/locales/json_api.en.yml +21 -0
  16. data/lib/infinum_json_api_setup/error.rb +61 -0
  17. data/lib/infinum_json_api_setup/json_api/content_negotiation.rb +29 -0
  18. data/lib/infinum_json_api_setup/json_api/error_handling.rb +49 -0
  19. data/lib/infinum_json_api_setup/json_api/error_serializer.rb +72 -0
  20. data/lib/infinum_json_api_setup/json_api/request_parsing.rb +17 -0
  21. data/lib/infinum_json_api_setup/json_api/responder.rb +31 -0
  22. data/lib/infinum_json_api_setup/json_api/serializer_options.rb +76 -0
  23. data/lib/infinum_json_api_setup/rails.rb +28 -0
  24. data/lib/infinum_json_api_setup/rspec/helpers/request_helper.rb +80 -0
  25. data/lib/infinum_json_api_setup/rspec/helpers/response_helper.rb +56 -0
  26. data/lib/infinum_json_api_setup/rspec/matchers/have_empty_data.rb +32 -0
  27. data/lib/infinum_json_api_setup/rspec/matchers/have_error_pointer.rb +37 -0
  28. data/lib/infinum_json_api_setup/rspec/matchers/have_resource_count_of.rb +37 -0
  29. data/lib/infinum_json_api_setup/rspec/matchers/include_all_resource_ids.rb +51 -0
  30. data/lib/infinum_json_api_setup/rspec/matchers/include_all_resource_ids_sorted.rb +21 -0
  31. data/lib/infinum_json_api_setup/rspec/matchers/include_all_resource_string_ids.rb +17 -0
  32. data/lib/infinum_json_api_setup/rspec/matchers/include_error_detail.rb +37 -0
  33. data/lib/infinum_json_api_setup/rspec/matchers/include_related_resource.rb +42 -0
  34. data/lib/infinum_json_api_setup/rspec/matchers/json_body_matcher.rb +42 -0
  35. data/lib/infinum_json_api_setup/rspec/matchers/schema_matchers.rb +29 -0
  36. data/lib/infinum_json_api_setup/rspec.rb +21 -0
  37. data/lib/infinum_json_api_setup/version.rb +3 -0
  38. data/lib/infinum_json_api_setup.rb +16 -0
  39. data/spec/controllers/api/v1/base_controller_spec.rb +9 -0
  40. data/spec/dummy/Rakefile +6 -0
  41. data/spec/dummy/app/assets/config/manifest.js +1 -0
  42. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  43. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  44. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  45. data/spec/dummy/app/controllers/api/v1/base_controller.rb +11 -0
  46. data/spec/dummy/app/controllers/api/v1/locations_controller.rb +64 -0
  47. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  48. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  49. data/spec/dummy/app/javascript/packs/application.js +15 -0
  50. data/spec/dummy/app/jobs/application_job.rb +7 -0
  51. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  52. data/spec/dummy/app/models/application_record.rb +3 -0
  53. data/spec/dummy/app/models/concerns/.keep +0 -0
  54. data/spec/dummy/app/models/location.rb +38 -0
  55. data/spec/dummy/app/models/location_label.rb +3 -0
  56. data/spec/dummy/app/policies/application_policy.rb +51 -0
  57. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  58. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  59. data/spec/dummy/app/web/api/v1/locations/label_serializer.rb +13 -0
  60. data/spec/dummy/app/web/api/v1/locations/policy.rb +28 -0
  61. data/spec/dummy/app/web/api/v1/locations/query.rb +12 -0
  62. data/spec/dummy/app/web/api/v1/locations/serializer.rb +15 -0
  63. data/spec/dummy/bin/rails +4 -0
  64. data/spec/dummy/bin/rake +4 -0
  65. data/spec/dummy/bin/setup +33 -0
  66. data/spec/dummy/config/application.rb +39 -0
  67. data/spec/dummy/config/boot.rb +5 -0
  68. data/spec/dummy/config/cable.yml +10 -0
  69. data/spec/dummy/config/database.yml +15 -0
  70. data/spec/dummy/config/environment.rb +5 -0
  71. data/spec/dummy/config/environments/development.rb +65 -0
  72. data/spec/dummy/config/environments/production.rb +114 -0
  73. data/spec/dummy/config/environments/test.rb +60 -0
  74. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  75. data/spec/dummy/config/initializers/backtrace_silencers.rb +10 -0
  76. data/spec/dummy/config/initializers/cors.rb +16 -0
  77. data/spec/dummy/config/initializers/filter_parameter_logging.rb +6 -0
  78. data/spec/dummy/config/initializers/inflections.rb +16 -0
  79. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  80. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  81. data/spec/dummy/config/locales/en.yml +33 -0
  82. data/spec/dummy/config/locales/json_api.en.yml +21 -0
  83. data/spec/dummy/config/puma.rb +43 -0
  84. data/spec/dummy/config/routes.rb +7 -0
  85. data/spec/dummy/config/storage.yml +34 -0
  86. data/spec/dummy/config.ru +6 -0
  87. data/spec/dummy/db/migrate/20210709100750_create_locations.rb +10 -0
  88. data/spec/dummy/db/migrate/20210714104736_create_location_labels.rb +10 -0
  89. data/spec/dummy/db/schema.rb +34 -0
  90. data/spec/dummy/log/.keep +0 -0
  91. data/spec/dummy/storage/.keep +0 -0
  92. data/spec/factories/location.rb +11 -0
  93. data/spec/factories/location_label.rb +6 -0
  94. data/spec/infinum_json_api_setup/rspec/matchers/have_empty_data_spec.rb +43 -0
  95. data/spec/infinum_json_api_setup/rspec/matchers/have_error_pointer_spec.rb +43 -0
  96. data/spec/infinum_json_api_setup/rspec/matchers/have_resource_count_of_spec.rb +43 -0
  97. data/spec/infinum_json_api_setup/rspec/matchers/include_all_resource_ids_sorted_spec.rb +53 -0
  98. data/spec/infinum_json_api_setup/rspec/matchers/include_all_resource_ids_spec.rb +49 -0
  99. data/spec/infinum_json_api_setup/rspec/matchers/include_all_resource_string_ids_spec.rb +49 -0
  100. data/spec/infinum_json_api_setup/rspec/matchers/include_error_detail_spec.rb +43 -0
  101. data/spec/infinum_json_api_setup/rspec/matchers/include_related_resource_spec.rb +43 -0
  102. data/spec/infinum_json_api_setup/rspec/matchers/util/body_parser.rb +30 -0
  103. data/spec/rails_helper.rb +77 -0
  104. data/spec/requests/api/v1/content_negotiation_spec.rb +29 -0
  105. data/spec/requests/api/v1/error_handling_spec.rb +114 -0
  106. data/spec/requests/api/v1/responder_spec.rb +91 -0
  107. data/spec/requests/api/v1/serializer_options_spec.rb +46 -0
  108. data/spec/spec_helper.rb +94 -0
  109. data/spec/support/factory_bot.rb +7 -0
  110. data/spec/support/infinum_json_api_setup.rb +1 -0
  111. data/spec/support/rspec_expectations.rb +5 -0
  112. data/spec/support/test_helpers/matchers/response.rb +17 -0
  113. data/spec/support/test_helpers/request.rb +11 -0
  114. data/spec/support/test_helpers/response.rb +8 -0
  115. metadata +351 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 59daa791c91a766c904582a3ca9399c6a18cb8c98dedbd77e00e4ac6a09eabd8
4
+ data.tar.gz: 353a09469052bb6177dc8105120f3bb45e4da7056f59f4f6a89a78349da1da72
5
+ SHA512:
6
+ metadata.gz: 524c5e641919c2bd20628750731bc469d739bfa6ebc2847ae7cf6300d7d7ab38ed5f514bca70e643da513e3c4fa7c3ca55aa62adf19db7c581f3a147bb96d5b7
7
+ data.tar.gz: 10b48c0f0322478d378dab1e0adbcdc97eed949067cd4c38d34bbdc743cfc421eb480fae6d7ff2510869cfeb8c8e575cbf47fd764ac12481ce1c8e6b74541b4b
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ /spec/examples.txt
2
+ /spec/dummy/log/*.log
3
+ /test/dummy/storage/
4
+ /spec/dummy/tmp/
5
+
6
+ coverage
data/.overcommit.yml ADDED
@@ -0,0 +1,26 @@
1
+ gemfile: Gemfile
2
+
3
+ CommitMsg:
4
+ HardTabs:
5
+ enabled: true
6
+
7
+ PreCommit:
8
+ BundleAudit:
9
+ enabled: true
10
+ flags: ['--update']
11
+ on_warn: fail
12
+ command: ['bundle', 'exec', 'bundle-audit']
13
+
14
+ BundleCheck:
15
+ enabled: true
16
+
17
+ RuboCop:
18
+ enabled: true
19
+ on_warn: fail
20
+ command: ['bundle', 'exec', 'rubocop']
21
+
22
+ TrailingWhitespace:
23
+ enabled: true
24
+
25
+ HardTabs:
26
+ enabled: true
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require rails_helper
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,29 @@
1
+ inherit_gem:
2
+ rubocop-infinum: rubocop.yml
3
+
4
+ require:
5
+ - rubocop-infinum
6
+ - rubocop-rake
7
+
8
+ Metrics/BlockLength:
9
+ Exclude:
10
+ - 'spec/**/*_spec.rb'
11
+
12
+ RSpec/ExampleLength:
13
+ Max: 10
14
+
15
+ RSpec/MultipleExpectations:
16
+ Max: 5
17
+
18
+ Style/AccessorGrouping:
19
+ EnforcedStyle: separated
20
+
21
+ Style/FrozenStringLiteralComment:
22
+ Enabled: false
23
+
24
+ AllCops:
25
+ TargetRubyVersion: 2.7
26
+ Exclude:
27
+ - 'spec/dummy/db/schema.rb'
28
+ - 'spec/dummy/db/migrate/*.rb'
29
+ NewCops: enable
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.7.2
data/.simplecov ADDED
@@ -0,0 +1,3 @@
1
+ SimpleCov.start do
2
+ add_filter %r{/spec/dummy}
3
+ end
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'bundler-audit', require: false
4
+ gem 'factory_bot', '~> 6.2'
5
+ gem 'faker', '~> 2.18'
6
+ gem 'rubocop', '~> 1.0', require: false
7
+ gem 'rubocop-infinum', require: false
8
+ gem 'rubocop-rake', require: false
9
+
10
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,268 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ infinum_json_api_setup (0.0.3)
5
+ json_schemer (~> 0.2)
6
+ jsonapi_parameters
7
+ pagy
8
+ rails
9
+ responders
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ actioncable (6.1.4.1)
15
+ actionpack (= 6.1.4.1)
16
+ activesupport (= 6.1.4.1)
17
+ nio4r (~> 2.0)
18
+ websocket-driver (>= 0.6.1)
19
+ actionmailbox (6.1.4.1)
20
+ actionpack (= 6.1.4.1)
21
+ activejob (= 6.1.4.1)
22
+ activerecord (= 6.1.4.1)
23
+ activestorage (= 6.1.4.1)
24
+ activesupport (= 6.1.4.1)
25
+ mail (>= 2.7.1)
26
+ actionmailer (6.1.4.1)
27
+ actionpack (= 6.1.4.1)
28
+ actionview (= 6.1.4.1)
29
+ activejob (= 6.1.4.1)
30
+ activesupport (= 6.1.4.1)
31
+ mail (~> 2.5, >= 2.5.4)
32
+ rails-dom-testing (~> 2.0)
33
+ actionpack (6.1.4.1)
34
+ actionview (= 6.1.4.1)
35
+ activesupport (= 6.1.4.1)
36
+ rack (~> 2.0, >= 2.0.9)
37
+ rack-test (>= 0.6.3)
38
+ rails-dom-testing (~> 2.0)
39
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
40
+ actiontext (6.1.4.1)
41
+ actionpack (= 6.1.4.1)
42
+ activerecord (= 6.1.4.1)
43
+ activestorage (= 6.1.4.1)
44
+ activesupport (= 6.1.4.1)
45
+ nokogiri (>= 1.8.5)
46
+ actionview (6.1.4.1)
47
+ activesupport (= 6.1.4.1)
48
+ builder (~> 3.1)
49
+ erubi (~> 1.4)
50
+ rails-dom-testing (~> 2.0)
51
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
52
+ activejob (6.1.4.1)
53
+ activesupport (= 6.1.4.1)
54
+ globalid (>= 0.3.6)
55
+ activemodel (6.1.4.1)
56
+ activesupport (= 6.1.4.1)
57
+ activerecord (6.1.4.1)
58
+ activemodel (= 6.1.4.1)
59
+ activesupport (= 6.1.4.1)
60
+ activestorage (6.1.4.1)
61
+ actionpack (= 6.1.4.1)
62
+ activejob (= 6.1.4.1)
63
+ activerecord (= 6.1.4.1)
64
+ activesupport (= 6.1.4.1)
65
+ marcel (~> 1.0.0)
66
+ mini_mime (>= 1.1.0)
67
+ activesupport (6.1.4.1)
68
+ concurrent-ruby (~> 1.0, >= 1.0.2)
69
+ i18n (>= 1.6, < 2)
70
+ minitest (>= 5.1)
71
+ tzinfo (~> 2.0)
72
+ zeitwerk (~> 2.3)
73
+ ast (2.4.2)
74
+ builder (3.2.4)
75
+ bundler-audit (0.8.0)
76
+ bundler (>= 1.2.0, < 3)
77
+ thor (~> 1.0)
78
+ childprocess (4.1.0)
79
+ coderay (1.1.3)
80
+ concurrent-ruby (1.1.9)
81
+ crass (1.0.6)
82
+ diff-lcs (1.4.4)
83
+ docile (1.4.0)
84
+ ecma-re-validator (0.3.0)
85
+ regexp_parser (~> 2.0)
86
+ erubi (1.10.0)
87
+ factory_bot (6.2.0)
88
+ activesupport (>= 5.0.0)
89
+ faker (2.18.0)
90
+ i18n (>= 1.6, < 2)
91
+ globalid (0.5.2)
92
+ activesupport (>= 5.0)
93
+ hana (1.3.7)
94
+ i18n (1.8.10)
95
+ concurrent-ruby (~> 1.0)
96
+ iniparse (1.5.0)
97
+ json_schemer (0.2.18)
98
+ ecma-re-validator (~> 0.3)
99
+ hana (~> 1.3)
100
+ regexp_parser (~> 2.0)
101
+ uri_template (~> 0.7)
102
+ jsonapi-query_builder (0.1.9)
103
+ activerecord (>= 5)
104
+ pagy (~> 3.5)
105
+ jsonapi-serializer (2.2.0)
106
+ activesupport (>= 4.2)
107
+ jsonapi_parameters (2.3.0)
108
+ actionpack (>= 4.1.8)
109
+ activesupport (>= 4.1.8)
110
+ loofah (2.12.0)
111
+ crass (~> 1.0.2)
112
+ nokogiri (>= 1.5.9)
113
+ mail (2.7.1)
114
+ mini_mime (>= 0.1.1)
115
+ marcel (1.0.1)
116
+ method_source (1.0.0)
117
+ mini_mime (1.1.1)
118
+ mini_portile2 (2.6.1)
119
+ minitest (5.14.4)
120
+ nio4r (2.5.8)
121
+ nokogiri (1.12.4)
122
+ mini_portile2 (~> 2.6.1)
123
+ racc (~> 1.4)
124
+ overcommit (0.58.0)
125
+ childprocess (>= 0.6.3, < 5)
126
+ iniparse (~> 1.4)
127
+ rexml (~> 3.2)
128
+ pagy (3.13.0)
129
+ parallel (1.20.1)
130
+ parser (3.0.2.0)
131
+ ast (~> 2.4.1)
132
+ pg (1.2.3)
133
+ pry (0.14.1)
134
+ coderay (~> 1.1)
135
+ method_source (~> 1.0)
136
+ pry-rails (0.3.9)
137
+ pry (>= 0.10.4)
138
+ pundit (2.1.0)
139
+ activesupport (>= 3.0.0)
140
+ racc (1.5.2)
141
+ rack (2.2.3)
142
+ rack-test (1.1.0)
143
+ rack (>= 1.0, < 3)
144
+ rails (6.1.4.1)
145
+ actioncable (= 6.1.4.1)
146
+ actionmailbox (= 6.1.4.1)
147
+ actionmailer (= 6.1.4.1)
148
+ actionpack (= 6.1.4.1)
149
+ actiontext (= 6.1.4.1)
150
+ actionview (= 6.1.4.1)
151
+ activejob (= 6.1.4.1)
152
+ activemodel (= 6.1.4.1)
153
+ activerecord (= 6.1.4.1)
154
+ activestorage (= 6.1.4.1)
155
+ activesupport (= 6.1.4.1)
156
+ bundler (>= 1.15.0)
157
+ railties (= 6.1.4.1)
158
+ sprockets-rails (>= 2.0.0)
159
+ rails-dom-testing (2.0.3)
160
+ activesupport (>= 4.2.0)
161
+ nokogiri (>= 1.6)
162
+ rails-html-sanitizer (1.4.2)
163
+ loofah (~> 2.3)
164
+ railties (6.1.4.1)
165
+ actionpack (= 6.1.4.1)
166
+ activesupport (= 6.1.4.1)
167
+ method_source
168
+ rake (>= 0.13)
169
+ thor (~> 1.0)
170
+ rainbow (3.0.0)
171
+ rake (13.0.6)
172
+ regexp_parser (2.1.1)
173
+ responders (3.0.1)
174
+ actionpack (>= 5.0)
175
+ railties (>= 5.0)
176
+ rexml (3.2.5)
177
+ rspec-core (3.10.1)
178
+ rspec-support (~> 3.10.0)
179
+ rspec-expectations (3.10.1)
180
+ diff-lcs (>= 1.2.0, < 2.0)
181
+ rspec-support (~> 3.10.0)
182
+ rspec-mocks (3.10.2)
183
+ diff-lcs (>= 1.2.0, < 2.0)
184
+ rspec-support (~> 3.10.0)
185
+ rspec-rails (5.0.1)
186
+ actionpack (>= 5.2)
187
+ activesupport (>= 5.2)
188
+ railties (>= 5.2)
189
+ rspec-core (~> 3.10)
190
+ rspec-expectations (~> 3.10)
191
+ rspec-mocks (~> 3.10)
192
+ rspec-support (~> 3.10)
193
+ rspec-support (3.10.2)
194
+ rubocop (1.20.0)
195
+ parallel (~> 1.10)
196
+ parser (>= 3.0.0.0)
197
+ rainbow (>= 2.2.2, < 4.0)
198
+ regexp_parser (>= 1.8, < 3.0)
199
+ rexml
200
+ rubocop-ast (>= 1.9.1, < 2.0)
201
+ ruby-progressbar (~> 1.7)
202
+ unicode-display_width (>= 1.4.0, < 3.0)
203
+ rubocop-ast (1.11.0)
204
+ parser (>= 3.0.1.1)
205
+ rubocop-infinum (0.5.0)
206
+ rubocop
207
+ rubocop-performance
208
+ rubocop-rails
209
+ rubocop-rspec
210
+ rubocop-performance (1.11.5)
211
+ rubocop (>= 1.7.0, < 2.0)
212
+ rubocop-ast (>= 0.4.0)
213
+ rubocop-rails (2.11.3)
214
+ activesupport (>= 4.2.0)
215
+ rack (>= 1.1)
216
+ rubocop (>= 1.7.0, < 2.0)
217
+ rubocop-rake (0.6.0)
218
+ rubocop (~> 1.0)
219
+ rubocop-rspec (2.4.0)
220
+ rubocop (~> 1.0)
221
+ rubocop-ast (>= 1.1.0)
222
+ ruby-progressbar (1.11.0)
223
+ simplecov (0.21.2)
224
+ docile (~> 1.1)
225
+ simplecov-html (~> 0.11)
226
+ simplecov_json_formatter (~> 0.1)
227
+ simplecov-html (0.12.3)
228
+ simplecov_json_formatter (0.1.3)
229
+ sprockets (4.0.2)
230
+ concurrent-ruby (~> 1.0)
231
+ rack (> 1, < 3)
232
+ sprockets-rails (3.2.2)
233
+ actionpack (>= 4.0)
234
+ activesupport (>= 4.0)
235
+ sprockets (>= 3.0.0)
236
+ thor (1.1.0)
237
+ tzinfo (2.0.4)
238
+ concurrent-ruby (~> 1.0)
239
+ unicode-display_width (2.0.0)
240
+ uri_template (0.7.0)
241
+ websocket-driver (0.7.5)
242
+ websocket-extensions (>= 0.1.0)
243
+ websocket-extensions (0.1.5)
244
+ zeitwerk (2.4.2)
245
+
246
+ PLATFORMS
247
+ ruby
248
+
249
+ DEPENDENCIES
250
+ bundler-audit
251
+ factory_bot (~> 6.2)
252
+ faker (~> 2.18)
253
+ infinum_json_api_setup!
254
+ jsonapi-query_builder
255
+ jsonapi-serializer
256
+ overcommit (~> 0.58)
257
+ pg
258
+ pry-rails
259
+ pundit
260
+ rake
261
+ rspec-rails (~> 5.0)
262
+ rubocop (~> 1.0)
263
+ rubocop-infinum
264
+ rubocop-rake
265
+ simplecov
266
+
267
+ BUNDLED WITH
268
+ 2.1.4
data/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # Infinum JSON:API setup
2
+ Preconfigured set of libraries for building JSON:API compliant endpoints, with matchers for writing more declarative JSON:API specs. This library presumes host project is compliant with using
3
+ - [rails](https://github.com/rails/rails) as an application server
4
+ - [jsonapi_parameters](https://github.com/visualitypl/jsonapi_parameters) for incoming data parsing
5
+ - [json_schemer](https://github.com/davishmcclurg/json_schemer) for validating JSON structures
6
+ - [responders](https://github.com/heartcombo/responders) for writing declarative actions
7
+
8
+ ## Installation
9
+ 1. Add Infinum JSON:API setup to your Gemfile
10
+ ```ruby
11
+ gem 'infinum_json_api_setup', github: 'infinum/infinum-json-api-setup'
12
+ ```
13
+
14
+ 2. Next, run the generator
15
+ ```bash
16
+ bundle exec rails generate infinum_json_api_setup:install
17
+ ```
18
+ The generator will copy the [default translations](https://github.com/infinum/infinum-json-api-setup/blob/master/lib/generators/infinum_json_api_setup/templates/config/locales/json_api.en.yml) into the host project (`config/locales/json_api.en.yml`), where they can be customized.
19
+
20
+ ## Application configuration
21
+ Create abstract class for your controllers, include common JSON:API request processing behaviour, and configure responders.
22
+ ```ruby
23
+ module Api
24
+ class BaseController < ActionController::API
25
+ include InfinumJsonApiSetup::JsonApi::ErrorHandling
26
+ include InfinumJsonApiSetup::JsonApi::ContentNegotiation
27
+
28
+ self.responder = InfinumJsonApiSetup::JsonApi::Responder
29
+ respond_to :json_api
30
+ end
31
+ end
32
+ ```
33
+
34
+ ## Basic usage
35
+
36
+ ### Permitted parameter handling
37
+ Use [jsonapi_parameters](https://github.com/visualitypl/jsonapi_parameters) to transform incoming JSON:API compliant data into common Rails parameters
38
+ ```ruby
39
+ def permitted_params
40
+ params.from_jsonapi
41
+ .require(:user)
42
+ .permit(:first_name, :last_name)
43
+ end
44
+ ```
45
+
46
+ ### Responding
47
+ Use `respond_with` to initiate transformation (serialization) of domain objects into HTTP response.
48
+ ```ruby
49
+ def show
50
+ respond_with User.find(params[:id])
51
+ end
52
+ ```
53
+
54
+ `respond_with` is well integrated with `ActiveRecord::Model` interface. Given a compliant object, the method will correctly set a response status and handle object(or error) serialization based on the presence of `.errors`. For a successful domain operation, HTTP status will be 200 OK (or 201 in case of `create` controller action). Unsuccessful operations will have HTTP status 422 Unprocessable Entity with errors structured according to [JSON:API specification](https://jsonapi.org/format/#error-objects).
55
+ ```ruby
56
+ def create
57
+ respond_with User.create(permitted_params)
58
+ end
59
+ ```
60
+
61
+ `respond_with` also detects usage from a `destroy` controller action and responds with HTTP status 204 No Content and an empty body.
62
+ ```ruby
63
+ def destroy
64
+ respond_with User.destroy(params[:id])
65
+ end
66
+ ```
67
+
68
+ ## Internals
69
+ This section explains the under-the-hood behavior of the library.
70
+
71
+ ### Content negotiation
72
+ `InfinumJsonApiSetup::JsonApi::ContentNegotiation` module is designed to integrate [server responsibilities](https://jsonapi.org/format/#content-negotiation-servers) of content negotiation protocol described by the JSON:API specification.
73
+
74
+ ### Error handling
75
+ `InfinumJsonApiSetup::JsonApi::ErrorHandling` module is designed to catch and handle common exceptions that might bubble up when processing a request.
76
+
77
+ | Exception | HTTP status | Bugsnag notification |
78
+ | --- | :---: | :---: |
79
+ | `ActionController::ParameterMissing` | 400 | |
80
+ | `ActionDispatch::Http::Parameters::ParseError` | 400 | |
81
+ | `Jure::UnpermittedSortParameters` | 400 | :white_check_mark: |
82
+ | `I18n::InvalidLocale` | 400 | |
83
+ | `Pundit::NotAuthorizedError` | 403 | :white_check_mark: |
84
+ | `ActiveRecord::RecordNotFound` | 404 | |
85
+ | `PG::Error` | 500 | |
86
+
87
+ ### Error serialization
88
+ `InfinumJsonApiSetup::JsonApi::ErrorSerializer` is responsible for serializing domain errors according to [JSON:API specification](https://jsonapi.org/format/#error-objects).
89
+
90
+ ## Testing
91
+
92
+ ### RSpec configuration
93
+ Library ships with a set of declarative matchers and request/response helpers. To use them in your specs, configure your RSpec setup in the following way which
94
+ - includes all defined matchers
95
+ - includes request and response helper methods into specs tagged with `:request` metadata
96
+ - configures search paths for resolving JSON schema files
97
+ ```ruby
98
+ require 'infinum_json_api_setup/rspec'
99
+
100
+ RSpec.configure do |config|
101
+ # Helpers
102
+ config.include InfinumJsonApiSetup::Rspec::Helpers::RequestHelper, type: :request
103
+ config.include InfinumJsonApiSetup::Rspec::Helpers::ResponseHelper, type: :request
104
+
105
+ # Schema paths
106
+ config.schema_response_root = Rails.application.root.join('path/to/response_schemas')
107
+ config.schema_request_root = Rails.application.root.join('path/to/request_schemas')
108
+ end
109
+ ```
110
+ ### Matchers
111
+
112
+ #### Have empty data
113
+ ```ruby
114
+ expect(response).to have_empty_data
115
+ ```
116
+
117
+ #### Have error pointer
118
+ ```ruby
119
+ expect(response).to have_error_pointer('data/attributes/first_name')
120
+ ```
121
+
122
+ #### Have resource count of
123
+ ```ruby
124
+ expect(response).to have_resource_count_of(3)
125
+ ```
126
+
127
+ #### Include all resource ids
128
+ ```ruby
129
+ expect(response).to include_all_resource_ids(records.map(&:id))
130
+ ```
131
+
132
+ #### Include all resource ids sorted
133
+ ```ruby
134
+ expect(response).to include_all_resource_ids_sorted(records.map(&:id))
135
+ ```
136
+
137
+ #### Include all resource string ids
138
+ ```ruby
139
+ expect(response).to include_all_resource_string_ids(records.map(&:id).map(&:to_s))
140
+ ```
141
+
142
+ #### Include error detail
143
+ ```ruby
144
+ expect(response).to include_error_detail('name has been taken')
145
+ ```
146
+
147
+ #### Include related resource
148
+ ```ruby
149
+ expect(response).to include_related_resource('user', user.id)
150
+ ```
151
+
152
+ ## Credits
153
+ **JSON:API setup** is maintained and sponsored by [Infinum](https://infinum.co)
154
+
155
+ ## License
156
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
data/bin/setup ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ require 'pathname'
3
+
4
+ GEM_ROOT = Pathname.new File.expand_path('..', __dir__)
5
+ DUMMY_APP_ROOT = Pathname.new File.expand_path('../spec/dummy', __dir__)
6
+
7
+ Dir.chdir GEM_ROOT do
8
+ puts '== Installing dependencies =='
9
+ system 'gem install bundler --conservative'
10
+ system 'bundle check || bundle install'
11
+
12
+ puts '== Installing overcommit =='
13
+ system 'overcommit --install'
14
+ end
15
+
16
+ Dir.chdir DUMMY_APP_ROOT do
17
+ system 'bin/setup'
18
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('./lib/infinum_json_api_setup/version', __dir__)
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = 'infinum_json_api_setup'
5
+ s.version = InfinumJsonApiSetup::VERSION
6
+ s.summary = 'Infinum JSON:API setup'
7
+ s.description = 'Preconfigured setup for building JSON:API endpoints'
8
+ s.authors = ['Team Backend @ Infinum']
9
+ s.email = 'team.backend@infinum.com'
10
+ s.files = `git ls-files`.split("\n")
11
+ s.homepage = 'https://github.com/infinum/infinum-json-api-setup'
12
+ s.license = 'MIT'
13
+ s.required_ruby_version = '> 2.7' # NOTE: randomly selected
14
+
15
+ s.add_runtime_dependency 'jsonapi_parameters' # TODO: define version
16
+ s.add_runtime_dependency 'json_schemer', '~> 0.2'
17
+ s.add_runtime_dependency 'pagy' # TODO: define version
18
+ s.add_runtime_dependency 'rails' # TODO: define version
19
+ s.add_runtime_dependency 'responders' # TODO: define version
20
+
21
+ s.add_development_dependency 'jsonapi-query_builder'
22
+ s.add_development_dependency 'jsonapi-serializer'
23
+ s.add_development_dependency 'overcommit', '~> 0.58'
24
+ s.add_development_dependency 'pg'
25
+ s.add_development_dependency 'pry-rails'
26
+ s.add_development_dependency 'pundit'
27
+ s.add_development_dependency 'rake'
28
+ s.add_development_dependency 'rspec-rails', '~> 5.0'
29
+ s.add_development_dependency 'simplecov'
30
+ end
@@ -0,0 +1,12 @@
1
+ module InfinumJsonApiSetup
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('templates', __dir__)
5
+ desc 'Copy default translations'
6
+
7
+ def copy_locale
8
+ copy_file 'config/locales/json_api.en.yml', 'config/locales/json_api.en.yml'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ en:
2
+ json_api:
3
+ errors:
4
+ bad_request:
5
+ title: Bad Request
6
+ detail: Bad request
7
+ not_found:
8
+ title: Not found
9
+ detail: Resource not found
10
+ forbidden:
11
+ title: Forbidden
12
+ detail: You are not allowed to perform this action
13
+ unauthorized:
14
+ title: Unauthorized
15
+ detail: Must be logged in to perform this action
16
+ unprocessable_entity:
17
+ title: Unprocessable Entity
18
+ detail: Cannot process request
19
+ internal_server_error:
20
+ title: Internal Server Error
21
+ detail: Something went wrong
@@ -0,0 +1,61 @@
1
+ module InfinumJsonApiSetup
2
+ module Error
3
+ class Base
4
+ # @return [String]
5
+ attr_reader :details
6
+
7
+ # @return [String]
8
+ attr_reader :title
9
+
10
+ # @param [Hash] opts
11
+ # @option opts [Object] :object
12
+ # @option opts [String] :message
13
+ def initialize(object: nil, message: nil)
14
+ @details =
15
+ details_from_object(object) || message || I18n.t("json_api.errors.#{http_status}.detail")
16
+ @title = I18n.t("json_api.errors.#{http_status}.title")
17
+ end
18
+
19
+ # @return [String]
20
+ def code
21
+ self.class.name.demodulize.underscore.upcase
22
+ end
23
+
24
+ # @return [Symbol]
25
+ def http_status
26
+ self.class.name.demodulize.underscore.to_sym
27
+ end
28
+
29
+ private
30
+
31
+ def details_from_object(object)
32
+ return unless object_supported?(object)
33
+
34
+ object.errors.map { |error| [error.attribute, error.full_message] }
35
+ end
36
+
37
+ def object_supported?(object)
38
+ object.present? && object.respond_to?(:errors) && object.errors.is_a?(ActiveModel::Errors)
39
+ end
40
+ end
41
+
42
+ class Forbidden < Base; end
43
+
44
+ class BadRequest < Base; end
45
+
46
+ class Gone < Base; end
47
+
48
+ class Unauthorized < Base; end
49
+
50
+ class UnprocessableEntity < Base; end
51
+
52
+ class InternalServerError < Base; end
53
+
54
+ class RecordNotFound < Base
55
+ # @return [Symbol]
56
+ def http_status
57
+ :not_found
58
+ end
59
+ end
60
+ end
61
+ end