README.md in graphql-batch-0.3.10 vs README.md in graphql-batch-0.4.0

- old
+ new

@@ -23,10 +23,12 @@ ## Usage ### Basic Usage +#### Schema Configuration + Require the library ```ruby require 'graphql/batch' ``` @@ -47,12 +49,13 @@ ``` Use `GraphQL::Batch` as a plugin in your schema (for graphql >= `1.5.0`). ```ruby -MySchema = GraphQL::Schema.define do +class MySchema < GraphQL::Schema query MyQueryType + mutation MyMutationType use GraphQL::Batch end ``` @@ -64,20 +67,43 @@ GraphQL::Batch.use(self) end ``` -The loader class can be used from the resolve proc for a graphql field by calling `.for` with the grouping arguments to get a loader instance, then call `.load` on that instance with the key to load. +##### With `1.9.0`'s `Interpreter` runtime +Add `GraphQL::Batch` _after_ the interpreter, so that `GraphQL::Batch` can detect the interpreter and attach the right integrations: + ```ruby -resolve -> (obj, args, context) { RecordLoader.for(Product).load(args["id"]) } +use GraphQL::Execution::Interpreter +use GraphQL::Batch ``` +#### Field Usage + +The loader class can be used from the resolver for a graphql field by calling `.for` with the grouping arguments to get a loader instance, then call `.load` on that instance with the key to load. + +```ruby +field :product, Types::Product, null: true do + argument :id, ID, required: true +end + +def product(id:) + RecordLoader.for(Product).load(id) +end +``` + The loader also supports batch loading an array of records instead of just a single record, via `load_many`. For example: ```ruby -resolve -> (obj, args, context) { RecordLoader.for(Product).load_many(args["ids"]) } +field :products, [Types::Product, null: true], null: false do + argument :ids, [ID], required: true +end + +def product(ids:) + RecordLoader.for(Product).load_many(ids) +end ``` Although this library doesn't have a dependency on active record, the [examples directory](examples) has record and association loaders for active record which handles edge cases like type casting ids @@ -87,31 +113,31 @@ ### Promises GraphQL::Batch::Loader#load returns a Promise using the [promise.rb gem](https://rubygems.org/gems/promise.rb) to provide a promise based API, so you can transform the query results using `.then` ```ruby -resolve -> (obj, args, context) do - RecordLoader.for(Product).load(args["id"]).then do |product| +def product_title(id:) + RecordLoader.for(Product).load(id).then do |product| product.title end end ``` You may also need to do another query that depends on the first one to get the result, in which case the query block can return another query. ```ruby -resolve -> (obj, args, context) do - RecordLoader.for(Product).load(args["id"]).then do |product| +def product_image(id:) + RecordLoader.for(Product).load(id).then do |product| RecordLoader.for(Image).load(product.image_id) end end ``` If the second query doesn't depend on the first one, then you can use Promise.all, which allows each query in the group to be batched with other queries. ```ruby -resolve -> (obj, args, context) do +def all_collections Promise.all([ CountLoader.for(Shop, :smart_collections).load(context.shop_id), CountLoader.for(Shop, :custom_collections).load(context.shop_id), ]).then do |results| results.reduce(&:+) @@ -120,11 +146,13 @@ ``` `.then` can optionally take two lambda arguments, the first of which is equivalent to passing a block to `.then`, and the second one handles exceptions. This can be used to provide a fallback ```ruby -resolve -> (obj, args, context) do +def product(id:) + # Try the cache first ... CacheLoader.for(Product).load(args["id"]).then(nil, lambda do |exc| + # But if there's a connection error, go to the underlying database raise exc unless exc.is_a?(Redis::BaseConnectionError) logger.warn err.message RecordLoader.for(Product).load(args["id"]) end) end