graphiti 2.0.0.beta.7 → 2.0.0.beta.8
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.
- checksums.yaml +4 -4
- data/.git-blame-ignore-revs +2 -0
- data/.github/workflows/ci.yml +55 -3
- data/.github/workflows/docs.yml +1 -1
- data/.github/workflows/notify-example-app.yml +18 -0
- data/.gitignore +2 -0
- data/.standard.yml +6 -0
- data/CHANGELOG.md +45 -0
- data/CONTRIBUTING.md +3 -1
- data/README.md +13 -206
- data/Rakefile +6 -3
- data/UPGRADING.md +1 -1
- data/graphiti.gemspec +8 -4
- data/lib/generators/graphiti/generator_mixin.rb +1 -1
- data/lib/generators/graphiti/install_generator.rb +1 -1
- data/lib/generators/graphiti/resource_generator.rb +6 -3
- data/lib/generators/graphiti/templates/application_resource.rb.erb +19 -0
- data/lib/generators/graphiti/templates/controller.rb.erb +26 -8
- data/lib/graphiti/audit/report.rb +6 -6
- data/lib/graphiti/audit.rb +3 -4
- data/lib/graphiti/delegates/pagination.rb +2 -2
- data/lib/graphiti/deserializer.rb +3 -3
- data/lib/graphiti/errors.rb +6 -6
- data/lib/graphiti/extensions/temp_id.rb +1 -1
- data/lib/graphiti/query.rb +3 -3
- data/lib/graphiti/rails/context.rb +2 -1
- data/lib/graphiti/rails/controller.rb +3 -0
- data/lib/graphiti/rails/debugging.rb +1 -1
- data/lib/graphiti/rails/responders.rb +2 -1
- data/lib/graphiti/resource/configuration.rb +1 -0
- data/lib/graphiti/resource/dsl.rb +2 -2
- data/lib/graphiti/resource/links.rb +1 -1
- data/lib/graphiti/resource/persistence.rb +1 -1
- data/lib/graphiti/resource/polymorphism.rb +1 -1
- data/lib/graphiti/resource.rb +2 -2
- data/lib/graphiti/resource_proxy.rb +0 -1
- data/lib/graphiti/scoping/filter.rb +5 -3
- data/lib/graphiti/scoping/paginate.rb +1 -1
- data/lib/graphiti/scoping/sort.rb +1 -1
- data/lib/graphiti/sideload/has_many.rb +1 -1
- data/lib/graphiti/spec_helpers/errors_proxy.rb +1 -1
- data/lib/graphiti/spec_helpers/matchers.rb +1 -1
- data/lib/graphiti/types.rb +5 -1
- data/lib/graphiti/util/cache_debug.rb +3 -3
- data/lib/graphiti/util/hash.rb +1 -1
- data/lib/graphiti/util/persistence.rb +6 -6
- data/lib/graphiti/util/serializer_relationships.rb +1 -1
- data/lib/graphiti/version.rb +1 -1
- data/lib/tasks/graphiti.rake +1 -1
- metadata +31 -197
- data/docs/concepts/backends-and-models.md +0 -122
- data/docs/concepts/endpoints.md +0 -183
- data/docs/concepts/links.md +0 -212
- data/docs/concepts/overview.md +0 -80
- data/docs/concepts/persisting.md +0 -376
- data/docs/concepts/relationships.md +0 -627
- data/docs/concepts/resources.md +0 -677
- data/docs/getting-started/first-api.md +0 -289
- data/docs/getting-started/installation.md +0 -185
- data/docs/intro.md +0 -307
- data/docs/js/authentication.md +0 -63
- data/docs/js/ddau.md +0 -20
- data/docs/js/extra-params.md +0 -41
- data/docs/js/index.md +0 -112
- data/docs/js/installation.md +0 -120
- data/docs/js/middleware.md +0 -72
- data/docs/js/models.md +0 -202
- data/docs/js/reads.md +0 -494
- data/docs/js/state-syncing.md +0 -100
- data/docs/js/writes.md +0 -373
- data/docs/reference/vandal.md +0 -63
- data/docs/reference/why.md +0 -13
- data/docs/topics/authorization.md +0 -155
- data/docs/topics/caching.md +0 -55
- data/docs/topics/customizing-sideloads.md +0 -156
- data/docs/topics/debugging.md +0 -242
- data/docs/topics/error-handling.md +0 -210
- data/docs/topics/etags.md +0 -46
- data/docs/topics/hopping-relationships.md +0 -149
- data/docs/topics/json-attributes.md +0 -77
- data/docs/topics/openstruct-models.md +0 -50
- data/docs/topics/remote-resources.md +0 -291
- data/docs/topics/testing.md +0 -916
- data/docs/topics/without-activerecord.md +0 -324
- data/docs/tutorial/index.md +0 -58
- data/docs/tutorial/step_0.md +0 -107
- data/docs/tutorial/step_1.md +0 -199
- data/docs/tutorial/step_2.md +0 -312
- data/docs/tutorial/step_3.md +0 -142
- data/docs/tutorial/step_4.md +0 -135
- data/docs/tutorial/step_5.md +0 -69
- data/docs/tutorial/step_6.md +0 -82
- data/docs/tutorial/step_7.md +0 -205
- data/docs/tutorial/step_8.md +0 -128
- data/docs/tutorial/step_9.md +0 -171
- data/docs/upgrading.md +0 -267
- data/website/.gitignore +0 -20
- data/website/README.md +0 -43
- data/website/docusaurus.config.js +0 -197
- data/website/package-lock.json +0 -19474
- data/website/package.json +0 -46
- data/website/sidebars.js +0 -82
- data/website/src/css/custom.css +0 -85
- data/website/src/pages/markdown-page.mdx +0 -7
- data/website/static/.nojekyll +0 -0
- data/website/static/1.13/2019/03/31/graphiti-1-0.html +0 -205
- data/website/static/1.13/2019/05/08/graphiti-1-1.html +0 -212
- data/website/static/1.13/2019/05/20/graphiti-1-2.html +0 -214
- data/website/static/1.13/2019/10/14/tutorial.html +0 -198
- data/website/static/1.13/CNAME +0 -1
- data/website/static/1.13/README.md +0 -16
- data/website/static/1.13/assets/css/syntax.css +0 -60
- data/website/static/1.13/assets/favicons/android-chrome-192x192.png +0 -0
- data/website/static/1.13/assets/favicons/android-chrome-256x256.png +0 -0
- data/website/static/1.13/assets/favicons/apple-touch-icon.png +0 -0
- data/website/static/1.13/assets/favicons/browserconfig.xml +0 -9
- data/website/static/1.13/assets/favicons/favicon-16x16.png +0 -0
- data/website/static/1.13/assets/favicons/favicon-32x32.png +0 -0
- data/website/static/1.13/assets/favicons/favicon.ico +0 -0
- data/website/static/1.13/assets/favicons/mstile-150x150.png +0 -0
- data/website/static/1.13/assets/favicons/safari-pinned-tab.svg +0 -1
- data/website/static/1.13/assets/favicons/site.webmanifest +0 -19
- data/website/static/1.13/assets/img/backend.gif +0 -0
- data/website/static/1.13/assets/img/conformity.png +0 -0
- data/website/static/1.13/assets/img/error_payload.png +0 -0
- data/website/static/1.13/assets/img/fancy-cushion.png +0 -0
- data/website/static/1.13/assets/img/gh.png +0 -0
- data/website/static/1.13/assets/img/home-bg.jpg +0 -0
- data/website/static/1.13/assets/img/lifecycle.gif +0 -0
- data/website/static/1.13/assets/img/logo-500.png +0 -0
- data/website/static/1.13/assets/img/logo.png +0 -0
- data/website/static/1.13/assets/img/love-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/meta_total_count.png +0 -0
- data/website/static/1.13/assets/img/persist.jpg +0 -0
- data/website/static/1.13/assets/img/resource.gif +0 -0
- data/website/static/1.13/assets/img/rest-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/rest1.gif +0 -0
- data/website/static/1.13/assets/img/rest2.gif +0 -0
- data/website/static/1.13/assets/img/rest3.gif +0 -0
- data/website/static/1.13/assets/img/rethink-rest-graffiti.jpg +0 -0
- data/website/static/1.13/assets/img/sunrise.png +0 -0
- data/website/static/1.13/assets/img/why.png +0 -0
- data/website/static/1.13/assets/js/highlight.pack.js +0 -2
- data/website/static/1.13/assets/main.css +0 -15518
- data/website/static/1.13/assets/main.css.map +0 -1
- data/website/static/1.13/bin/bundle +0 -109
- data/website/static/1.13/bin/jekyll +0 -27
- data/website/static/1.13/bin/kramdown +0 -27
- data/website/static/1.13/bin/listen +0 -27
- data/website/static/1.13/bin/rake +0 -27
- data/website/static/1.13/bin/rougify +0 -27
- data/website/static/1.13/bin/safe_yaml +0 -27
- data/website/static/1.13/bin/sass +0 -27
- data/website/static/1.13/bin/sass-convert +0 -27
- data/website/static/1.13/bin/scss +0 -27
- data/website/static/1.13/blog.html +0 -259
- data/website/static/1.13/cheatsheet.html +0 -316
- data/website/static/1.13/cookbooks/authorization.md +0 -0
- data/website/static/1.13/cookbooks/caching.md +0 -0
- data/website/static/1.13/cookbooks/customizing-sideloads.html +0 -325
- data/website/static/1.13/cookbooks/etags.md +0 -0
- data/website/static/1.13/cookbooks/hopping-relationships.html +0 -324
- data/website/static/1.13/cookbooks/json_attributes.md +0 -0
- data/website/static/1.13/cookbooks/openstruct-models.md +0 -0
- data/website/static/1.13/cookbooks/remote-resources.md +0 -0
- data/website/static/1.13/cookbooks/without-activerecord.html +0 -510
- data/website/static/1.13/features.html +0 -249
- data/website/static/1.13/feed.xml +0 -106
- data/website/static/1.13/guides/concepts/backends-and-models.html +0 -467
- data/website/static/1.13/guides/concepts/debugging.html +0 -440
- data/website/static/1.13/guides/concepts/endpoints.html +0 -432
- data/website/static/1.13/guides/concepts/error-handling.html +0 -396
- data/website/static/1.13/guides/concepts/links.html +0 -501
- data/website/static/1.13/guides/concepts/remote-resources.html +0 -536
- data/website/static/1.13/guides/concepts/resources.html +0 -2176
- data/website/static/1.13/guides/concepts/testing.html +0 -1469
- data/website/static/1.13/guides/getting-started/installation.html +0 -420
- data/website/static/1.13/guides/graphiti-rails-migration.html +0 -242
- data/website/static/1.13/guides/index.html +0 -269
- data/website/static/1.13/guides/overview.html +0 -325
- data/website/static/1.13/guides/upgrading-2-0.html +0 -193
- data/website/static/1.13/guides/upgrading.html +0 -314
- data/website/static/1.13/guides/vandal.html +0 -282
- data/website/static/1.13/guides/why.html +0 -1121
- data/website/static/1.13/index.html +0 -72
- data/website/static/1.13/js/authentication.html +0 -295
- data/website/static/1.13/js/ddau.html +0 -238
- data/website/static/1.13/js/extra-params.html +0 -270
- data/website/static/1.13/js/index.html +0 -321
- data/website/static/1.13/js/installation.html +0 -637
- data/website/static/1.13/js/introduction.html +0 -257
- data/website/static/1.13/js/middleware.html +0 -318
- data/website/static/1.13/js/reads/fieldsets.html +0 -271
- data/website/static/1.13/js/reads/filtering.html +0 -289
- data/website/static/1.13/js/reads/includes.html +0 -260
- data/website/static/1.13/js/reads/index.html +0 -497
- data/website/static/1.13/js/reads/nested-queries.html +0 -353
- data/website/static/1.13/js/reads/pagination.html +0 -260
- data/website/static/1.13/js/reads/sorting.html +0 -265
- data/website/static/1.13/js/reads/statistics.html +0 -289
- data/website/static/1.13/js/state-syncing.html +0 -340
- data/website/static/1.13/js/writes/deferred.html +0 -296
- data/website/static/1.13/js/writes/dirty-tracking.html +0 -399
- data/website/static/1.13/js/writes/index.html +0 -391
- data/website/static/1.13/js/writes/nested.html +0 -330
- data/website/static/1.13/js/writes/validations.html +0 -272
- data/website/static/1.13/quickstart.html +0 -660
- data/website/static/1.13/template +0 -161
- data/website/static/1.13/tutorial/index.html +0 -250
- data/website/static/1.13/tutorial/step_0.html +0 -292
- data/website/static/1.13/tutorial/step_1.html +0 -517
- data/website/static/1.13/tutorial/step_2.html +0 -481
- data/website/static/1.13/tutorial/step_3.html +0 -323
- data/website/static/1.13/tutorial/step_4.html +0 -318
- data/website/static/1.13/tutorial/step_5.html +0 -265
- data/website/static/1.13/tutorial/step_6.html +0 -276
- data/website/static/1.13/tutorial/step_7.html +0 -390
- data/website/static/1.13/tutorial/step_8.html +0 -316
- data/website/static/1.13/tutorial/step_9.html +0 -365
- data/website/static/CNAME +0 -1
- data/website/static/assets/img/error_payload.png +0 -0
- data/website/static/assets/img/legacy/legacy-0378a3bb39.png +0 -0
- data/website/static/assets/img/legacy/legacy-05bbd3e5fd.png +0 -0
- data/website/static/assets/img/legacy/legacy-07aa104495.png +0 -0
- data/website/static/assets/img/legacy/legacy-0c75a16b3a.gif +0 -0
- data/website/static/assets/img/legacy/legacy-3076df6209.png +0 -0
- data/website/static/assets/img/legacy/legacy-7f6889bc89.png +0 -0
- data/website/static/assets/img/legacy/legacy-a2cc4363c3.png +0 -0
- data/website/static/assets/img/legacy/legacy-f67cfa89ab.png +0 -0
- data/website/static/assets/img/meta_total_count.png +0 -0
- data/website/static/img/docusaurus-social-card.jpg +0 -0
- data/website/static/img/docusaurus.png +0 -0
- data/website/static/img/favicon.ico +0 -0
- data/website/static/img/logo.png +0 -0
- data/website/static/img/logo.svg +0 -1
- data/website/static/img/undraw_docusaurus_mountain.svg +0 -171
- data/website/static/img/undraw_docusaurus_react.svg +0 -170
- 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.
|
|
4
|
+
version: 2.0.0.beta.8
|
|
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
|
|
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
|
|
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: '
|
|
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: '
|
|
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.
|
|
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.
|
|
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
|
|
@@ -434,148 +410,6 @@ files:
|
|
|
434
410
|
- lib/tasks/graphiti.rake
|
|
435
411
|
- package-lock.json
|
|
436
412
|
- 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
413
|
homepage: https://github.com/graphiti-api/graphiti
|
|
580
414
|
licenses:
|
|
581
415
|
- MIT
|
|
@@ -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.
|
data/docs/concepts/endpoints.md
DELETED
|
@@ -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).
|