graphiti 2.0.0.beta.7 → 2.0.0.beta.9

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 (251) hide show
  1. checksums.yaml +4 -4
  2. data/.git-blame-ignore-revs +2 -0
  3. data/.github/workflows/ci.yml +56 -4
  4. data/.github/workflows/docs.yml +10 -7
  5. data/.github/workflows/notify-example-app.yml +18 -0
  6. data/.github/workflows/release.yml +1 -1
  7. data/.gitignore +2 -0
  8. data/.standard.yml +6 -0
  9. data/CHANGELOG.md +66 -0
  10. data/CONTRIBUTING.md +3 -1
  11. data/README.md +13 -206
  12. data/Rakefile +34 -3
  13. data/UPGRADING.md +2 -2
  14. data/graphiti.gemspec +8 -4
  15. data/lib/generators/graphiti/generator_mixin.rb +1 -1
  16. data/lib/generators/graphiti/install_generator.rb +1 -1
  17. data/lib/generators/graphiti/resource_generator.rb +6 -3
  18. data/lib/generators/graphiti/templates/application_resource.rb.erb +19 -0
  19. data/lib/generators/graphiti/templates/controller.rb.erb +26 -8
  20. data/lib/graphiti/audit/report.rb +6 -6
  21. data/lib/graphiti/audit.rb +3 -4
  22. data/lib/graphiti/configuration.rb +11 -4
  23. data/lib/graphiti/debugger.rb +18 -6
  24. data/lib/graphiti/delegates/pagination.rb +2 -2
  25. data/lib/graphiti/deserializer.rb +3 -3
  26. data/lib/graphiti/error_serializers/deprecated_constants.rb +23 -0
  27. data/lib/graphiti/error_serializers/invalid_request.rb +6 -0
  28. data/lib/graphiti/errors.rb +22 -6
  29. data/lib/graphiti/extensions/temp_id.rb +1 -1
  30. data/lib/graphiti/query.rb +5 -4
  31. data/lib/graphiti/rails/context.rb +2 -1
  32. data/lib/graphiti/rails/controller.rb +3 -0
  33. data/lib/graphiti/rails/debugging.rb +1 -1
  34. data/lib/graphiti/rails/responders.rb +2 -1
  35. data/lib/graphiti/rails.rb +14 -0
  36. data/lib/graphiti/railtie.rb +8 -0
  37. data/lib/graphiti/resource/configuration.rb +1 -0
  38. data/lib/graphiti/resource/dsl.rb +2 -2
  39. data/lib/graphiti/resource/links.rb +1 -1
  40. data/lib/graphiti/resource/persistence.rb +1 -1
  41. data/lib/graphiti/resource/polymorphism.rb +1 -1
  42. data/lib/graphiti/resource.rb +2 -2
  43. data/lib/graphiti/resource_proxy.rb +0 -1
  44. data/lib/graphiti/scope.rb +68 -21
  45. data/lib/graphiti/scoping/filter.rb +5 -3
  46. data/lib/graphiti/scoping/paginate.rb +1 -1
  47. data/lib/graphiti/scoping/sort.rb +1 -1
  48. data/lib/graphiti/sideload/has_many.rb +1 -1
  49. data/lib/graphiti/sideload/polymorphic_belongs_to.rb +11 -4
  50. data/lib/graphiti/sideload.rb +8 -6
  51. data/lib/graphiti/spec_helpers/errors_proxy.rb +1 -1
  52. data/lib/graphiti/spec_helpers/matchers.rb +1 -1
  53. data/lib/graphiti/types.rb +5 -1
  54. data/lib/graphiti/util/cache_debug.rb +3 -3
  55. data/lib/graphiti/util/hash.rb +1 -1
  56. data/lib/graphiti/util/persistence.rb +6 -6
  57. data/lib/graphiti/util/serializer_relationships.rb +11 -2
  58. data/lib/graphiti/version.rb +1 -1
  59. data/lib/graphiti.rb +1 -1
  60. data/lib/tasks/graphiti.rake +1 -1
  61. data/package-lock.json +114 -0
  62. data/package.json +16 -3
  63. metadata +33 -198
  64. data/docs/concepts/backends-and-models.md +0 -122
  65. data/docs/concepts/endpoints.md +0 -183
  66. data/docs/concepts/links.md +0 -212
  67. data/docs/concepts/overview.md +0 -80
  68. data/docs/concepts/persisting.md +0 -376
  69. data/docs/concepts/relationships.md +0 -627
  70. data/docs/concepts/resources.md +0 -677
  71. data/docs/getting-started/first-api.md +0 -289
  72. data/docs/getting-started/installation.md +0 -185
  73. data/docs/intro.md +0 -307
  74. data/docs/js/authentication.md +0 -63
  75. data/docs/js/ddau.md +0 -20
  76. data/docs/js/extra-params.md +0 -41
  77. data/docs/js/index.md +0 -112
  78. data/docs/js/installation.md +0 -120
  79. data/docs/js/middleware.md +0 -72
  80. data/docs/js/models.md +0 -202
  81. data/docs/js/reads.md +0 -494
  82. data/docs/js/state-syncing.md +0 -100
  83. data/docs/js/writes.md +0 -373
  84. data/docs/reference/vandal.md +0 -63
  85. data/docs/reference/why.md +0 -13
  86. data/docs/topics/authorization.md +0 -155
  87. data/docs/topics/caching.md +0 -55
  88. data/docs/topics/customizing-sideloads.md +0 -156
  89. data/docs/topics/debugging.md +0 -242
  90. data/docs/topics/error-handling.md +0 -210
  91. data/docs/topics/etags.md +0 -46
  92. data/docs/topics/hopping-relationships.md +0 -149
  93. data/docs/topics/json-attributes.md +0 -77
  94. data/docs/topics/openstruct-models.md +0 -50
  95. data/docs/topics/remote-resources.md +0 -291
  96. data/docs/topics/testing.md +0 -916
  97. data/docs/topics/without-activerecord.md +0 -324
  98. data/docs/tutorial/index.md +0 -58
  99. data/docs/tutorial/step_0.md +0 -107
  100. data/docs/tutorial/step_1.md +0 -199
  101. data/docs/tutorial/step_2.md +0 -312
  102. data/docs/tutorial/step_3.md +0 -142
  103. data/docs/tutorial/step_4.md +0 -135
  104. data/docs/tutorial/step_5.md +0 -69
  105. data/docs/tutorial/step_6.md +0 -82
  106. data/docs/tutorial/step_7.md +0 -205
  107. data/docs/tutorial/step_8.md +0 -128
  108. data/docs/tutorial/step_9.md +0 -171
  109. data/docs/upgrading.md +0 -267
  110. data/website/.gitignore +0 -20
  111. data/website/README.md +0 -43
  112. data/website/docusaurus.config.js +0 -197
  113. data/website/package-lock.json +0 -19474
  114. data/website/package.json +0 -46
  115. data/website/sidebars.js +0 -82
  116. data/website/src/css/custom.css +0 -85
  117. data/website/src/pages/markdown-page.mdx +0 -7
  118. data/website/static/.nojekyll +0 -0
  119. data/website/static/1.13/2019/03/31/graphiti-1-0.html +0 -205
  120. data/website/static/1.13/2019/05/08/graphiti-1-1.html +0 -212
  121. data/website/static/1.13/2019/05/20/graphiti-1-2.html +0 -214
  122. data/website/static/1.13/2019/10/14/tutorial.html +0 -198
  123. data/website/static/1.13/CNAME +0 -1
  124. data/website/static/1.13/README.md +0 -16
  125. data/website/static/1.13/assets/css/syntax.css +0 -60
  126. data/website/static/1.13/assets/favicons/android-chrome-192x192.png +0 -0
  127. data/website/static/1.13/assets/favicons/android-chrome-256x256.png +0 -0
  128. data/website/static/1.13/assets/favicons/apple-touch-icon.png +0 -0
  129. data/website/static/1.13/assets/favicons/browserconfig.xml +0 -9
  130. data/website/static/1.13/assets/favicons/favicon-16x16.png +0 -0
  131. data/website/static/1.13/assets/favicons/favicon-32x32.png +0 -0
  132. data/website/static/1.13/assets/favicons/favicon.ico +0 -0
  133. data/website/static/1.13/assets/favicons/mstile-150x150.png +0 -0
  134. data/website/static/1.13/assets/favicons/safari-pinned-tab.svg +0 -1
  135. data/website/static/1.13/assets/favicons/site.webmanifest +0 -19
  136. data/website/static/1.13/assets/img/backend.gif +0 -0
  137. data/website/static/1.13/assets/img/conformity.png +0 -0
  138. data/website/static/1.13/assets/img/error_payload.png +0 -0
  139. data/website/static/1.13/assets/img/fancy-cushion.png +0 -0
  140. data/website/static/1.13/assets/img/gh.png +0 -0
  141. data/website/static/1.13/assets/img/home-bg.jpg +0 -0
  142. data/website/static/1.13/assets/img/lifecycle.gif +0 -0
  143. data/website/static/1.13/assets/img/logo-500.png +0 -0
  144. data/website/static/1.13/assets/img/logo.png +0 -0
  145. data/website/static/1.13/assets/img/love-graffiti.jpg +0 -0
  146. data/website/static/1.13/assets/img/meta_total_count.png +0 -0
  147. data/website/static/1.13/assets/img/persist.jpg +0 -0
  148. data/website/static/1.13/assets/img/resource.gif +0 -0
  149. data/website/static/1.13/assets/img/rest-graffiti.jpg +0 -0
  150. data/website/static/1.13/assets/img/rest1.gif +0 -0
  151. data/website/static/1.13/assets/img/rest2.gif +0 -0
  152. data/website/static/1.13/assets/img/rest3.gif +0 -0
  153. data/website/static/1.13/assets/img/rethink-rest-graffiti.jpg +0 -0
  154. data/website/static/1.13/assets/img/sunrise.png +0 -0
  155. data/website/static/1.13/assets/img/why.png +0 -0
  156. data/website/static/1.13/assets/js/highlight.pack.js +0 -2
  157. data/website/static/1.13/assets/main.css +0 -15518
  158. data/website/static/1.13/assets/main.css.map +0 -1
  159. data/website/static/1.13/bin/bundle +0 -109
  160. data/website/static/1.13/bin/jekyll +0 -27
  161. data/website/static/1.13/bin/kramdown +0 -27
  162. data/website/static/1.13/bin/listen +0 -27
  163. data/website/static/1.13/bin/rake +0 -27
  164. data/website/static/1.13/bin/rougify +0 -27
  165. data/website/static/1.13/bin/safe_yaml +0 -27
  166. data/website/static/1.13/bin/sass +0 -27
  167. data/website/static/1.13/bin/sass-convert +0 -27
  168. data/website/static/1.13/bin/scss +0 -27
  169. data/website/static/1.13/blog.html +0 -259
  170. data/website/static/1.13/cheatsheet.html +0 -316
  171. data/website/static/1.13/cookbooks/authorization.md +0 -0
  172. data/website/static/1.13/cookbooks/caching.md +0 -0
  173. data/website/static/1.13/cookbooks/customizing-sideloads.html +0 -325
  174. data/website/static/1.13/cookbooks/etags.md +0 -0
  175. data/website/static/1.13/cookbooks/hopping-relationships.html +0 -324
  176. data/website/static/1.13/cookbooks/json_attributes.md +0 -0
  177. data/website/static/1.13/cookbooks/openstruct-models.md +0 -0
  178. data/website/static/1.13/cookbooks/remote-resources.md +0 -0
  179. data/website/static/1.13/cookbooks/without-activerecord.html +0 -510
  180. data/website/static/1.13/features.html +0 -249
  181. data/website/static/1.13/feed.xml +0 -106
  182. data/website/static/1.13/guides/concepts/backends-and-models.html +0 -467
  183. data/website/static/1.13/guides/concepts/debugging.html +0 -440
  184. data/website/static/1.13/guides/concepts/endpoints.html +0 -432
  185. data/website/static/1.13/guides/concepts/error-handling.html +0 -396
  186. data/website/static/1.13/guides/concepts/links.html +0 -501
  187. data/website/static/1.13/guides/concepts/remote-resources.html +0 -536
  188. data/website/static/1.13/guides/concepts/resources.html +0 -2176
  189. data/website/static/1.13/guides/concepts/testing.html +0 -1469
  190. data/website/static/1.13/guides/getting-started/installation.html +0 -420
  191. data/website/static/1.13/guides/graphiti-rails-migration.html +0 -242
  192. data/website/static/1.13/guides/index.html +0 -269
  193. data/website/static/1.13/guides/overview.html +0 -325
  194. data/website/static/1.13/guides/upgrading-2-0.html +0 -193
  195. data/website/static/1.13/guides/upgrading.html +0 -314
  196. data/website/static/1.13/guides/vandal.html +0 -282
  197. data/website/static/1.13/guides/why.html +0 -1121
  198. data/website/static/1.13/index.html +0 -72
  199. data/website/static/1.13/js/authentication.html +0 -295
  200. data/website/static/1.13/js/ddau.html +0 -238
  201. data/website/static/1.13/js/extra-params.html +0 -270
  202. data/website/static/1.13/js/index.html +0 -321
  203. data/website/static/1.13/js/installation.html +0 -637
  204. data/website/static/1.13/js/introduction.html +0 -257
  205. data/website/static/1.13/js/middleware.html +0 -318
  206. data/website/static/1.13/js/reads/fieldsets.html +0 -271
  207. data/website/static/1.13/js/reads/filtering.html +0 -289
  208. data/website/static/1.13/js/reads/includes.html +0 -260
  209. data/website/static/1.13/js/reads/index.html +0 -497
  210. data/website/static/1.13/js/reads/nested-queries.html +0 -353
  211. data/website/static/1.13/js/reads/pagination.html +0 -260
  212. data/website/static/1.13/js/reads/sorting.html +0 -265
  213. data/website/static/1.13/js/reads/statistics.html +0 -289
  214. data/website/static/1.13/js/state-syncing.html +0 -340
  215. data/website/static/1.13/js/writes/deferred.html +0 -296
  216. data/website/static/1.13/js/writes/dirty-tracking.html +0 -399
  217. data/website/static/1.13/js/writes/index.html +0 -391
  218. data/website/static/1.13/js/writes/nested.html +0 -330
  219. data/website/static/1.13/js/writes/validations.html +0 -272
  220. data/website/static/1.13/quickstart.html +0 -660
  221. data/website/static/1.13/template +0 -161
  222. data/website/static/1.13/tutorial/index.html +0 -250
  223. data/website/static/1.13/tutorial/step_0.html +0 -292
  224. data/website/static/1.13/tutorial/step_1.html +0 -517
  225. data/website/static/1.13/tutorial/step_2.html +0 -481
  226. data/website/static/1.13/tutorial/step_3.html +0 -323
  227. data/website/static/1.13/tutorial/step_4.html +0 -318
  228. data/website/static/1.13/tutorial/step_5.html +0 -265
  229. data/website/static/1.13/tutorial/step_6.html +0 -276
  230. data/website/static/1.13/tutorial/step_7.html +0 -390
  231. data/website/static/1.13/tutorial/step_8.html +0 -316
  232. data/website/static/1.13/tutorial/step_9.html +0 -365
  233. data/website/static/CNAME +0 -1
  234. data/website/static/assets/img/error_payload.png +0 -0
  235. data/website/static/assets/img/legacy/legacy-0378a3bb39.png +0 -0
  236. data/website/static/assets/img/legacy/legacy-05bbd3e5fd.png +0 -0
  237. data/website/static/assets/img/legacy/legacy-07aa104495.png +0 -0
  238. data/website/static/assets/img/legacy/legacy-0c75a16b3a.gif +0 -0
  239. data/website/static/assets/img/legacy/legacy-3076df6209.png +0 -0
  240. data/website/static/assets/img/legacy/legacy-7f6889bc89.png +0 -0
  241. data/website/static/assets/img/legacy/legacy-a2cc4363c3.png +0 -0
  242. data/website/static/assets/img/legacy/legacy-f67cfa89ab.png +0 -0
  243. data/website/static/assets/img/meta_total_count.png +0 -0
  244. data/website/static/img/docusaurus-social-card.jpg +0 -0
  245. data/website/static/img/docusaurus.png +0 -0
  246. data/website/static/img/favicon.ico +0 -0
  247. data/website/static/img/logo.png +0 -0
  248. data/website/static/img/logo.svg +0 -1
  249. data/website/static/img/undraw_docusaurus_mountain.svg +0 -171
  250. data/website/static/img/undraw_docusaurus_react.svg +0 -170
  251. data/website/static/img/undraw_docusaurus_tree.svg +0 -40
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta.7
4
+ version: 2.0.0.beta.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
@@ -129,30 +129,36 @@ dependencies:
129
129
  name: faraday
130
130
  requirement: !ruby/object:Gem::Requirement
131
131
  requirements:
132
- - - "~>"
132
+ - - ">="
133
133
  - !ruby/object:Gem::Version
134
- version: '0.15'
134
+ version: '2.0'
135
+ - - "<"
136
+ - !ruby/object:Gem::Version
137
+ version: '3'
135
138
  type: :development
136
139
  prerelease: false
137
140
  version_requirements: !ruby/object:Gem::Requirement
138
141
  requirements:
139
- - - "~>"
142
+ - - ">="
140
143
  - !ruby/object:Gem::Version
141
- version: '0.15'
144
+ version: '2.0'
145
+ - - "<"
146
+ - !ruby/object:Gem::Version
147
+ version: '3'
142
148
  - !ruby/object:Gem::Dependency
143
149
  name: kaminari
144
150
  requirement: !ruby/object:Gem::Requirement
145
151
  requirements:
146
152
  - - "~>"
147
153
  - !ruby/object:Gem::Version
148
- version: '0.17'
154
+ version: '1.2'
149
155
  type: :development
150
156
  prerelease: false
151
157
  version_requirements: !ruby/object:Gem::Requirement
152
158
  requirements:
153
159
  - - "~>"
154
160
  - !ruby/object:Gem::Version
155
- version: '0.17'
161
+ version: '1.2'
156
162
  - !ruby/object:Gem::Dependency
157
163
  name: bundler
158
164
  requirement: !ruby/object:Gem::Requirement
@@ -187,14 +193,14 @@ dependencies:
187
193
  requirements:
188
194
  - - "~>"
189
195
  - !ruby/object:Gem::Version
190
- version: 1.4.0
196
+ version: '1.56'
191
197
  type: :development
192
198
  prerelease: false
193
199
  version_requirements: !ruby/object:Gem::Requirement
194
200
  requirements:
195
201
  - - "~>"
196
202
  - !ruby/object:Gem::Version
197
- version: 1.4.0
203
+ version: '1.56'
198
204
  - !ruby/object:Gem::Dependency
199
205
  name: activemodel
200
206
  requirement: !ruby/object:Gem::Requirement
@@ -209,6 +215,20 @@ dependencies:
209
215
  - - ">="
210
216
  - !ruby/object:Gem::Version
211
217
  version: '7.1'
218
+ - !ruby/object:Gem::Dependency
219
+ name: rexml
220
+ requirement: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ">="
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ type: :development
226
+ prerelease: false
227
+ version_requirements: !ruby/object:Gem::Requirement
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
212
232
  - !ruby/object:Gem::Dependency
213
233
  name: rspec
214
234
  requirement: !ruby/object:Gem::Requirement
@@ -230,9 +250,11 @@ executables:
230
250
  extensions: []
231
251
  extra_rdoc_files: []
232
252
  files:
253
+ - ".git-blame-ignore-revs"
233
254
  - ".github/probots.yml"
234
255
  - ".github/workflows/ci.yml"
235
256
  - ".github/workflows/docs.yml"
257
+ - ".github/workflows/notify-example-app.yml"
236
258
  - ".github/workflows/release.yml"
237
259
  - ".gitignore"
238
260
  - ".npmrc"
@@ -255,52 +277,6 @@ files:
255
277
  - bin/console
256
278
  - bin/rspec
257
279
  - bin/setup
258
- - docs/concepts/backends-and-models.md
259
- - docs/concepts/endpoints.md
260
- - docs/concepts/links.md
261
- - docs/concepts/overview.md
262
- - docs/concepts/persisting.md
263
- - docs/concepts/relationships.md
264
- - docs/concepts/resources.md
265
- - docs/getting-started/first-api.md
266
- - docs/getting-started/installation.md
267
- - docs/intro.md
268
- - docs/js/authentication.md
269
- - docs/js/ddau.md
270
- - docs/js/extra-params.md
271
- - docs/js/index.md
272
- - docs/js/installation.md
273
- - docs/js/middleware.md
274
- - docs/js/models.md
275
- - docs/js/reads.md
276
- - docs/js/state-syncing.md
277
- - docs/js/writes.md
278
- - docs/reference/vandal.md
279
- - docs/reference/why.md
280
- - docs/topics/authorization.md
281
- - docs/topics/caching.md
282
- - docs/topics/customizing-sideloads.md
283
- - docs/topics/debugging.md
284
- - docs/topics/error-handling.md
285
- - docs/topics/etags.md
286
- - docs/topics/hopping-relationships.md
287
- - docs/topics/json-attributes.md
288
- - docs/topics/openstruct-models.md
289
- - docs/topics/remote-resources.md
290
- - docs/topics/testing.md
291
- - docs/topics/without-activerecord.md
292
- - docs/tutorial/index.md
293
- - docs/tutorial/step_0.md
294
- - docs/tutorial/step_1.md
295
- - docs/tutorial/step_2.md
296
- - docs/tutorial/step_3.md
297
- - docs/tutorial/step_4.md
298
- - docs/tutorial/step_5.md
299
- - docs/tutorial/step_6.md
300
- - docs/tutorial/step_7.md
301
- - docs/tutorial/step_8.md
302
- - docs/tutorial/step_9.md
303
- - docs/upgrading.md
304
280
  - exe/graphiti
305
281
  - gemfiles/.bundle/config
306
282
  - gemfiles/rails_7_1.gemfile
@@ -364,6 +340,7 @@ files:
364
340
  - lib/graphiti/rails/rake_helpers.rb
365
341
  - lib/graphiti/rails/responders.rb
366
342
  - lib/graphiti/rails/test_helpers.rb
343
+ - lib/graphiti/railtie.rb
367
344
  - lib/graphiti/renderer.rb
368
345
  - lib/graphiti/request_validator.rb
369
346
  - lib/graphiti/request_validators/update_validator.rb
@@ -434,148 +411,6 @@ files:
434
411
  - lib/tasks/graphiti.rake
435
412
  - package-lock.json
436
413
  - package.json
437
- - website/.gitignore
438
- - website/README.md
439
- - website/docusaurus.config.js
440
- - website/package-lock.json
441
- - website/package.json
442
- - website/sidebars.js
443
- - website/src/css/custom.css
444
- - website/src/pages/markdown-page.mdx
445
- - website/static/.nojekyll
446
- - website/static/1.13/2019/03/31/graphiti-1-0.html
447
- - website/static/1.13/2019/05/08/graphiti-1-1.html
448
- - website/static/1.13/2019/05/20/graphiti-1-2.html
449
- - website/static/1.13/2019/10/14/tutorial.html
450
- - website/static/1.13/CNAME
451
- - website/static/1.13/README.md
452
- - website/static/1.13/assets/css/syntax.css
453
- - website/static/1.13/assets/favicons/android-chrome-192x192.png
454
- - website/static/1.13/assets/favicons/android-chrome-256x256.png
455
- - website/static/1.13/assets/favicons/apple-touch-icon.png
456
- - website/static/1.13/assets/favicons/browserconfig.xml
457
- - website/static/1.13/assets/favicons/favicon-16x16.png
458
- - website/static/1.13/assets/favicons/favicon-32x32.png
459
- - website/static/1.13/assets/favicons/favicon.ico
460
- - website/static/1.13/assets/favicons/mstile-150x150.png
461
- - website/static/1.13/assets/favicons/safari-pinned-tab.svg
462
- - website/static/1.13/assets/favicons/site.webmanifest
463
- - website/static/1.13/assets/img/backend.gif
464
- - website/static/1.13/assets/img/conformity.png
465
- - website/static/1.13/assets/img/error_payload.png
466
- - website/static/1.13/assets/img/fancy-cushion.png
467
- - website/static/1.13/assets/img/gh.png
468
- - website/static/1.13/assets/img/home-bg.jpg
469
- - website/static/1.13/assets/img/lifecycle.gif
470
- - website/static/1.13/assets/img/logo-500.png
471
- - website/static/1.13/assets/img/logo.png
472
- - website/static/1.13/assets/img/love-graffiti.jpg
473
- - website/static/1.13/assets/img/meta_total_count.png
474
- - website/static/1.13/assets/img/persist.jpg
475
- - website/static/1.13/assets/img/resource.gif
476
- - website/static/1.13/assets/img/rest-graffiti.jpg
477
- - website/static/1.13/assets/img/rest1.gif
478
- - website/static/1.13/assets/img/rest2.gif
479
- - website/static/1.13/assets/img/rest3.gif
480
- - website/static/1.13/assets/img/rethink-rest-graffiti.jpg
481
- - website/static/1.13/assets/img/sunrise.png
482
- - website/static/1.13/assets/img/why.png
483
- - website/static/1.13/assets/js/highlight.pack.js
484
- - website/static/1.13/assets/main.css
485
- - website/static/1.13/assets/main.css.map
486
- - website/static/1.13/bin/bundle
487
- - website/static/1.13/bin/jekyll
488
- - website/static/1.13/bin/kramdown
489
- - website/static/1.13/bin/listen
490
- - website/static/1.13/bin/rake
491
- - website/static/1.13/bin/rougify
492
- - website/static/1.13/bin/safe_yaml
493
- - website/static/1.13/bin/sass
494
- - website/static/1.13/bin/sass-convert
495
- - website/static/1.13/bin/scss
496
- - website/static/1.13/blog.html
497
- - website/static/1.13/cheatsheet.html
498
- - website/static/1.13/cookbooks/authorization.md
499
- - website/static/1.13/cookbooks/caching.md
500
- - website/static/1.13/cookbooks/customizing-sideloads.html
501
- - website/static/1.13/cookbooks/etags.md
502
- - website/static/1.13/cookbooks/hopping-relationships.html
503
- - website/static/1.13/cookbooks/json_attributes.md
504
- - website/static/1.13/cookbooks/openstruct-models.md
505
- - website/static/1.13/cookbooks/remote-resources.md
506
- - website/static/1.13/cookbooks/without-activerecord.html
507
- - website/static/1.13/features.html
508
- - website/static/1.13/feed.xml
509
- - website/static/1.13/guides/concepts/backends-and-models.html
510
- - website/static/1.13/guides/concepts/debugging.html
511
- - website/static/1.13/guides/concepts/endpoints.html
512
- - website/static/1.13/guides/concepts/error-handling.html
513
- - website/static/1.13/guides/concepts/links.html
514
- - website/static/1.13/guides/concepts/remote-resources.html
515
- - website/static/1.13/guides/concepts/resources.html
516
- - website/static/1.13/guides/concepts/testing.html
517
- - website/static/1.13/guides/getting-started/installation.html
518
- - website/static/1.13/guides/graphiti-rails-migration.html
519
- - website/static/1.13/guides/index.html
520
- - website/static/1.13/guides/overview.html
521
- - website/static/1.13/guides/upgrading-2-0.html
522
- - website/static/1.13/guides/upgrading.html
523
- - website/static/1.13/guides/vandal.html
524
- - website/static/1.13/guides/why.html
525
- - website/static/1.13/index.html
526
- - website/static/1.13/js/authentication.html
527
- - website/static/1.13/js/ddau.html
528
- - website/static/1.13/js/extra-params.html
529
- - website/static/1.13/js/index.html
530
- - website/static/1.13/js/installation.html
531
- - website/static/1.13/js/introduction.html
532
- - website/static/1.13/js/middleware.html
533
- - website/static/1.13/js/reads/fieldsets.html
534
- - website/static/1.13/js/reads/filtering.html
535
- - website/static/1.13/js/reads/includes.html
536
- - website/static/1.13/js/reads/index.html
537
- - website/static/1.13/js/reads/nested-queries.html
538
- - website/static/1.13/js/reads/pagination.html
539
- - website/static/1.13/js/reads/sorting.html
540
- - website/static/1.13/js/reads/statistics.html
541
- - website/static/1.13/js/state-syncing.html
542
- - website/static/1.13/js/writes/deferred.html
543
- - website/static/1.13/js/writes/dirty-tracking.html
544
- - website/static/1.13/js/writes/index.html
545
- - website/static/1.13/js/writes/nested.html
546
- - website/static/1.13/js/writes/validations.html
547
- - website/static/1.13/quickstart.html
548
- - website/static/1.13/template
549
- - website/static/1.13/tutorial/index.html
550
- - website/static/1.13/tutorial/step_0.html
551
- - website/static/1.13/tutorial/step_1.html
552
- - website/static/1.13/tutorial/step_2.html
553
- - website/static/1.13/tutorial/step_3.html
554
- - website/static/1.13/tutorial/step_4.html
555
- - website/static/1.13/tutorial/step_5.html
556
- - website/static/1.13/tutorial/step_6.html
557
- - website/static/1.13/tutorial/step_7.html
558
- - website/static/1.13/tutorial/step_8.html
559
- - website/static/1.13/tutorial/step_9.html
560
- - website/static/CNAME
561
- - website/static/assets/img/error_payload.png
562
- - website/static/assets/img/legacy/legacy-0378a3bb39.png
563
- - website/static/assets/img/legacy/legacy-05bbd3e5fd.png
564
- - website/static/assets/img/legacy/legacy-07aa104495.png
565
- - website/static/assets/img/legacy/legacy-0c75a16b3a.gif
566
- - website/static/assets/img/legacy/legacy-3076df6209.png
567
- - website/static/assets/img/legacy/legacy-7f6889bc89.png
568
- - website/static/assets/img/legacy/legacy-a2cc4363c3.png
569
- - website/static/assets/img/legacy/legacy-f67cfa89ab.png
570
- - website/static/assets/img/meta_total_count.png
571
- - website/static/img/docusaurus-social-card.jpg
572
- - website/static/img/docusaurus.png
573
- - website/static/img/favicon.ico
574
- - website/static/img/logo.png
575
- - website/static/img/logo.svg
576
- - website/static/img/undraw_docusaurus_mountain.svg
577
- - website/static/img/undraw_docusaurus_react.svg
578
- - website/static/img/undraw_docusaurus_tree.svg
579
414
  homepage: https://github.com/graphiti-api/graphiti
580
415
  licenses:
581
416
  - MIT
@@ -594,7 +429,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
594
429
  - !ruby/object:Gem::Version
595
430
  version: '0'
596
431
  requirements: []
597
- rubygems_version: 3.6.9
432
+ rubygems_version: 4.0.16
598
433
  specification_version: 4
599
434
  summary: Easily build jsonapi.org-compatible APIs
600
435
  test_files: []
@@ -1,122 +0,0 @@
1
- ---
2
- title: 'Backends and Models'
3
- ---
4
-
5
- # Backends and Models
6
-
7
- A Resource queries a **Backend** and returns **Models** from what comes back. Graphiti serializes the Models.
8
-
9
- With ActiveRecord those are the same object. `Employee` is both the thing you query and the thing you render, and you can skip most of this page. It matters when they're separate: a search index, an HTTP service, a document store. Then the Backend is whatever you query, and the Model is whatever you hand back.
10
-
11
- ## Scopes {#scopes}
12
-
13
- A **scope** is whatever your backend needs to run a query. Graphiti doesn't care what it is. For ActiveRecord it's an `ActiveRecord::Relation`. Here it's a plain hash:
14
-
15
- ```ruby
16
- class EmployeeResource < ApplicationResource
17
- self.adapter = Graphiti::Adapters::Null
18
-
19
- attribute :name, :string
20
-
21
- def base_scope
22
- { conditions: {}, sort: {} }
23
- end
24
-
25
- filter :name do
26
- eq do |scope, value|
27
- scope[:conditions].merge!(value)
28
- scope
29
- end
30
- end
31
-
32
- sort :name do |scope, direction|
33
- scope[:sort] = { name: direction }
34
- scope
35
- end
36
-
37
- def resolve(scope)
38
- results = Backend.query(scope)
39
- results.map { |result| Employee.new(result) }
40
- end
41
- end
42
- ```
43
-
44
- `base_scope` is the starting point, each `filter` and `sort` block mutates it based on request params, and `resolve` runs the query and returns Models.
45
-
46
- **Every block must return the scope.** Returning the result of `merge!` or an assignment instead of the scope itself is the most common way to break this.
47
-
48
- Writing that per Resource gets old. Once the pattern stabilizes, move it into an [Adapter](/topics/without-activerecord#adapters) and Resources go back to being declarative:
49
-
50
- ```ruby
51
- class EmployeeResource < ApplicationResource
52
- self.adapter = BackendAdapter
53
- attribute :name, :string
54
- end
55
- ```
56
-
57
- ## What a Model has to do {#model-requirements}
58
-
59
- **Respond to `id`, uniquely.** Graphiti uses `model.id` to tell records apart when rendering. Duplicate ids produce wrong output, not an error.
60
-
61
- If the underlying record has no id, generate one:
62
-
63
- ```ruby
64
- def id
65
- @id ||= SecureRandom.uuid
66
- end
67
- ```
68
-
69
- **Respond to its readable attributes.** `attribute :name, :string` calls `model.name`. If your Model doesn't have that method, pass a block instead:
70
-
71
- ```ruby
72
- attribute :name, :string do
73
- @object.full_name
74
- end
75
- ```
76
-
77
- **Include `ActiveModel::Validations` if you want validation errors.** Graphiti checks models on write requests and renders a [JSON:API errors payload](http://jsonapi.org/format/#errors) from `model.errors`. Without it, an invalid model saves silently:
78
-
79
- ```ruby
80
- class Employee
81
- include ActiveModel::Validations
82
-
83
- validates :name, presence: true
84
- end
85
- ```
86
-
87
- ## Writing a Model {#model-implementations}
88
-
89
- Graphiti has no opinion here. A plain class works:
90
-
91
- ```ruby
92
- class Employee
93
- attr_accessor :id, :first_name, :last_name, :age
94
-
95
- def initialize(attrs = {})
96
- attrs.each_pair { |key, value| send(:"#{key}=", value) }
97
- end
98
- end
99
- ```
100
-
101
- [ActiveModel::Model](https://api.rubyonrails.org/classes/ActiveModel/Model.html) gives you the constructor and validations for free:
102
-
103
- ```ruby
104
- class Employee
105
- include ActiveModel::Model
106
-
107
- attr_accessor :id, :first_name, :last_name, :age
108
- end
109
- ```
110
-
111
- [Dry::Struct](https://dry-rb.org/gems/dry-struct) adds type enforcement, and dry-types is already a Graphiti dependency:
112
-
113
- ```ruby
114
- class Employee < Dry::Struct
115
- attribute :id, Types::Integer
116
- attribute :first_name, Types::String
117
- attribute :last_name, Types::String
118
- attribute :age, Types::Integer
119
- end
120
- ```
121
-
122
- `OpenStruct` also works and is what Graphiti uses internally for remote resources, but it fails quietly in ways the others don't. See [OpenStruct Models](/topics/openstruct-models) before reaching for it.
@@ -1,183 +0,0 @@
1
- ---
2
- title: 'Endpoints'
3
- ---
4
-
5
- ## Overview {#overview}
6
-
7
- **Endpoints** expose and customize
8
- [Resources](/concepts/resources).
9
-
10
- Resources themselves can operate completely independently of a request or response:
11
-
12
- ```ruby
13
- employees = EmployeeResource.all({
14
- filter: { title: 'engineer' },
15
- sort: '-created_at',
16
- page: { size: 10 },
17
- include: 'positions.department'
18
- })
19
-
20
- employees.map(&:first_name) # => ['Jane', 'John', ...]
21
- employees.to_json # => { employees: [{ ... }] }
22
- ```
23
-
24
- And Resources connect to other Resources. Our graph of data is defined
25
- **outside** of the actual API.
26
-
27
- Endpoints expose this graph to the world. We might choose to have a `/employees` endpoint that can eager load comments (`?include=comments`), but never expose `/comments` directly. Or, we could do the opposite: expose lazy-loading `/comments`, but disallow eager loading from `/employees`. We can add caching rules, or add an `/exemplary_employees` endpoint with special query overrides.
28
-
29
- Finally, Endpoints are in charge of the [HTTP specification](https://tools.ietf.org/html/rfc2616):
30
- request processing, response codes, caching, MIME types, and so on. If you're thinking
31
- Rails, an Endpoint is the combination of a Route and Controller.
32
-
33
- ### Endpoint Logic {#endpoint-logic}
34
-
35
- Often, you won't need to customize Endpoints - especially if you're
36
- using our [Rails Resource
37
- generator](/concepts/resources#generators). Endpoint logic mostly
38
- concerns:
39
-
40
- * Caching
41
- * Side-effect behavior specific to the endpoint (e.g.: sending a
42
- welcome email from `/users#create` but not `/admin/users#create`)
43
- * Authorization (e.g `before_action`)
44
- * Custom query parameter handling
45
- * Validation handling
46
- * Error handling
47
- * Limiting Resource behavior
48
- * Customizing Resource behavior
49
-
50
- If your logic falls elsewhere, consider a Resource or Model.
51
-
52
- ### Rails Integration {#rails-integration}
53
-
54
- When using Rails, an endpoint is the combination of a Route and
55
- Controller:
56
-
57
- ```ruby
58
- # config/routes.rb
59
- resources :posts, only: [:index]
60
-
61
- # app/controllers/posts_controller.rb
62
- class PostsController < ApplicationController
63
- def index
64
- posts = PostResource.all(params)
65
- respond_with(posts)
66
- end
67
- end
68
- ```
69
-
70
- You'll note that Graphiti hooks into Rails with a mixin (set when using
71
- our application generator):
72
-
73
- ```ruby
74
- class ApplicationController < ActionController::API
75
- include Graphiti::Rails::Controller
76
-
77
- # ... code ...
78
- end
79
- ```
80
-
81
- This gives us [#sideload_allowlist](#sideload-allowlist) and sets the
82
- [context](/concepts/resources#context).
83
-
84
- ## Customizing Resources {#customizing-resources}
85
-
86
- ### Scope Overrides {#scope-overrides}
87
-
88
- One common use case for endpoints is customizing the Resource
89
- [base scope](/concepts/resources#base-scope). This causes a new
90
- "starting point" for query building.
91
-
92
- Consider the endpoints `/posts` (basic CRUD) and `/top_posts`. Though both are associated to PostResource, `/top_posts` ensures that only
93
- Posts with a certain number of upvotes get returned:
94
-
95
- ```ruby
96
- def index
97
- base_scope = Post.where("upvotes > ?", 100)
98
- posts = PostResource.all(params, base_scope)
99
- respond_with(posts)
100
- end
101
- ```
102
-
103
- We're able to reuse all the other logic in PostResource - relationships,
104
- filters, sorts, etc - while only returning "Top Posts".
105
-
106
- ### Sideload Allowlist {#sideload-allowlist}
107
-
108
- Resources define relationships to other resources. But we may not want
109
- all of those relationships exposed at a given endpoint.
110
-
111
- Let's say we've defined relationships:
112
-
113
- `Employee > Position > Department > Hardware > CostHistory`
114
-
115
- It's reasonable to get an Employee, their Positions, and Departments for
116
- those positions in a single request. But is it really valid to *also* pull down
117
- all the hardware, as well as all the historical data on the cost of that hardware,
118
- in a single request? Allowing the entire graph to be pulled down in a single request can cause excessive load on our
119
- servers (and this is probably a better fit for lazy-loading via
120
- [Links](/concepts/links)).
121
-
122
- Let's instead say that if we're entering the graph at `/employees`, the
123
- furthest we can go is Department:
124
-
125
- ```ruby
126
- class EmployeesController < ApplicationController
127
- self.sideload_allowlist = {
128
- index: { positions: 'department' }
129
- }
130
-
131
- # ... code ...
132
- end
133
- ```
134
-
135
- ## Caching {#caching}
136
-
137
- ### Etags {#etags}
138
-
139
- [ETags](https://robots.thoughtbot.com/introduction-to-conditional-http-caching-with-rails) are an important concept that is often overlooked. Etags tell browsers
140
- that the response to a GET request hasn't changed since the last request and
141
- can be safely pulled from the browser cache. If you care about sparse fieldsets,
142
- you should care about ETags - if you're limiting fields to reduce payload size,
143
- how about a payload size of **zero**?
144
-
145
- ETags are set by default in Rails, by checking the response body. This won't prevent queries from executing, but it will save clients from downloading the response again if nothing has changed.
146
-
147
- Let's manually set an ETag:
148
-
149
- ```ruby
150
- def index
151
- posts = PostResource.all(params)
152
-
153
- if stale?(posts.data)
154
- respond_with(posts)
155
- end
156
- end
157
- ```
158
-
159
- From the [documentation on #stale?](https://api.rubyonrails.org/classes/ActionController/ConditionalGet.html#method-i-stale-3F):
160
-
161
- > *In this case last_modified will be set by calling `maximum(:updated_at)` on the collection (the timestamp of the most recently updated record) and the etag by passing the object itself.*
162
-
163
- Also consider the use case where data is ingested hourly. We can avoid a
164
- query altogether by checking when the last ingestion ran:
165
-
166
- ```ruby
167
- def index
168
- if stale?(EmployeeIngestion.last)
169
- employees = EmployeeResource.all(params)
170
- respond_with(employees)
171
- end
172
- end
173
- ```
174
-
175
- > **CAVEAT**: When setting ETags, consider sideloads. In the above examples
176
- > we are checking to see the last update of an Employee, but we may be
177
- > sideloading (and filtering) Positions as well. Use custom endpoints or
178
- > [Sideload Allowlist](#sideload-allowlist) to mitigate this issue.
179
-
180
- ## Testing {#testing}
181
-
182
- If you have custom Endpoint logic, we suggest testing using an [API
183
- Test](/topics/testing#api-tests).