graphql-persisted_queries 0.1.3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b56768c7a951fcc1f1ef63fb0bcbe054c900b0a5636579b811f5e858ed1e57b
4
- data.tar.gz: 512044a14538d39037d5092860a739646771b5ad4d9deca2df522ce9ba1ef657
3
+ metadata.gz: 3121fbd184f715130c9f9f1956dcd89c24d52507d23ac0b35a408a9d53d54e72
4
+ data.tar.gz: 7e4b32a6b5d0fda8d9b135a435bca92587749ccb61664f37092c593ef4b04eb0
5
5
  SHA512:
6
- metadata.gz: f6359ac33469754e332377d2c5c945cf5ce94c13609efeb603f9d2d6b5db8c08af58c290cec1ca9aa85ff048894ff1edd61a517069348ac2ea6144e7c12f8291
7
- data.tar.gz: fe4f663992844109589ab001fe394e5c562f75c9eba9b95c6733f6b264a4531657a57952d7b10a30cb7692184592fa46b51cbfc89686dea358f7cbd061de3fd7
6
+ metadata.gz: a42f753183b5d8aa8c0d8f321a988b61375ad6ae828ef9c232e91f4f20adb5da824b6b095cb034af805e11039f5c7122d52add4cdb4caa36bb873335a85e5847
7
+ data.tar.gz: 539d3e7da1bed8a470555b2b411cd52a6631663e7f3927e0c9252988488800c205bfe10f4eb03b3baa34899e286420b9d743f411fefc54c9dc091a1406d75a96
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 0.2.0 (2020-02-11)
6
+
7
+ - [PR#17](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/17) Allow an optional custom error handler so that implementors can control failure scenarios when query resolution fails ([@bmorton][])
8
+
5
9
  ## 0.1.3 (2020-01-30)
6
10
 
7
11
  - [PR#15](https://github.com/DmitryTsepelev/graphql-ruby-persisted_queries/pull/15) Allow optional custom expiration and namespace for Redis store ([@bmorton][])
data/README.md CHANGED
@@ -115,6 +115,33 @@ class GraphqlSchema < GraphQL::Schema
115
115
  end
116
116
  ```
117
117
 
118
+ ## Error handling
119
+
120
+ You may optionally specify an object that will be called whenever an error occurs while attempting to resolve or save a query. This will give you the opportunity to both handle (e.g. graceful Redis failure) and/or log the error. By default, errors will be raised when a failure occurs within a `StoreAdapter`.
121
+
122
+ An error handler can be a proc or an implementation of `GraphQL::PersistedQueries::ErrorHandlers::BaseErrorHandler`. Here's an example for treating Redis failures as cache misses:
123
+
124
+ ```ruby
125
+ class GracefulRedisErrorHandler < GraphQL::PersistedQueries::ErrorHandlers::BaseErrorHandler
126
+ def call(error)
127
+ case error
128
+ when Redis::BaseError
129
+ # Treat Redis errors as a cache miss, but you should log the error into
130
+ # your instrumentation framework here.
131
+ else
132
+ raise error
133
+ end
134
+
135
+ # Return nothing to ensure handled errors are treated as cache misses
136
+ return
137
+ end
138
+ end
139
+
140
+ class GraphqlSchema < GraphQL::Schema
141
+ use GraphQL::PersistedQueries, error_handler: GracefulRedisErrorHandler.new
142
+ end
143
+ ```
144
+
118
145
  ## GET requests and HTTP cache
119
146
 
120
147
  Using `GET` requests for persisted queries allows you to enable HTTP caching (e.g., turn on CDN). In order to make it work you should change the way link is initialized on front-end side (`createPersistedQueryLink({ useGETForHashedQueries: true })`) and register a new route `get "/graphql", to: "graphql#execute"`.
@@ -1,17 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "graphql/persisted_queries/error_handlers"
3
4
  require "graphql/persisted_queries/schema_patch"
4
5
  require "graphql/persisted_queries/store_adapters"
5
6
  require "graphql/persisted_queries/version"
7
+ require "graphql/persisted_queries/builder_helpers"
6
8
 
7
9
  module GraphQL
8
10
  # Plugin definition
9
11
  module PersistedQueries
10
- def self.use(schema_defn, store: :memory, hash_generator: :sha256, **options)
12
+ def self.use(schema_defn, store: :memory, hash_generator: :sha256,
13
+ error_handler: :default, **options)
11
14
  schema = schema_defn.is_a?(Class) ? schema_defn : schema_defn.target
12
15
 
13
16
  schema.singleton_class.prepend(SchemaPatch)
14
17
  schema.hash_generator = hash_generator
18
+ schema.configure_persisted_query_error_handler(error_handler)
15
19
  schema.configure_persisted_query_store(store, options)
16
20
  end
17
21
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module PersistedQueries
5
+ # Contains factory methods for error handlers
6
+ module BuilderHelpers
7
+ def self.camelize(name)
8
+ name.to_s.split("_").map(&:capitalize).join
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "graphql/persisted_queries/error_handlers/base_error_handler"
4
+ require "graphql/persisted_queries/error_handlers/default_error_handler"
5
+
6
+ module GraphQL
7
+ module PersistedQueries
8
+ # Contains factory methods for error handlers
9
+ module ErrorHandlers
10
+ def self.build(handler, options = nil)
11
+ if handler.is_a?(ErrorHandlers::BaseErrorHandler)
12
+ handler
13
+ elsif handler.is_a?(Proc)
14
+ build_from_proc(handler)
15
+ else
16
+ build_by_name(handler, options)
17
+ end
18
+ end
19
+
20
+ def self.build_from_proc(proc)
21
+ if proc.arity != 1
22
+ raise ArgumentError, "proc passed to :error_handler should have exactly one argument"
23
+ end
24
+
25
+ proc
26
+ end
27
+
28
+ def self.build_by_name(name, options)
29
+ const_get("#{BuilderHelpers.camelize(name)}ErrorHandler").new(options || {})
30
+ rescue NameError => e
31
+ raise e.class, "Persisted query error handler for :#{name} haven't been found", e.backtrace
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module PersistedQueries
5
+ module ErrorHandlers
6
+ # Base class for all error handlers
7
+ class BaseErrorHandler
8
+ def initialize(_options); end
9
+
10
+ def call(_error)
11
+ raise NotImplementedError
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module GraphQL
4
+ module PersistedQueries
5
+ module ErrorHandlers
6
+ # Default error handler for simply re-raising the error
7
+ class DefaultErrorHandler < BaseErrorHandler
8
+ def call(error)
9
+ raise error
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -18,10 +18,11 @@ module GraphQL
18
18
  end
19
19
  end
20
20
 
21
- def initialize(extensions, store, hash_generator_proc)
21
+ def initialize(extensions, store, hash_generator_proc, error_handler)
22
22
  @extensions = extensions
23
23
  @store = store
24
24
  @hash_generator_proc = hash_generator_proc
25
+ @error_handler = error_handler
25
26
  end
26
27
 
27
28
  def resolve(query_str)
@@ -30,7 +31,7 @@ module GraphQL
30
31
  if query_str
31
32
  persist_query(query_str)
32
33
  else
33
- query_str = @store.fetch_query(hash)
34
+ query_str = with_error_handling { @store.fetch_query(hash) }
34
35
  raise NotFound if query_str.nil?
35
36
  end
36
37
 
@@ -39,10 +40,16 @@ module GraphQL
39
40
 
40
41
  private
41
42
 
43
+ def with_error_handling
44
+ yield
45
+ rescue StandardError => e
46
+ @error_handler.call(e)
47
+ end
48
+
42
49
  def persist_query(query_str)
43
50
  raise WrongHash if @hash_generator_proc.call(query_str) != hash
44
51
 
45
- @store.save_query(hash, query_str)
52
+ with_error_handling { @store.save_query(hash, query_str) }
46
53
  end
47
54
 
48
55
  def hash
@@ -7,19 +7,24 @@ module GraphQL
7
7
  module PersistedQueries
8
8
  # Patches GraphQL::Schema to support persisted queries
9
9
  module SchemaPatch
10
- attr_reader :persisted_query_store, :hash_generator_proc
10
+ attr_reader :persisted_query_store, :hash_generator_proc, :persisted_query_error_handler
11
11
 
12
12
  def configure_persisted_query_store(store, options)
13
13
  @persisted_query_store = StoreAdapters.build(store, options)
14
14
  end
15
15
 
16
+ def configure_persisted_query_error_handler(handler)
17
+ @persisted_query_error_handler = ErrorHandlers.build(handler)
18
+ end
19
+
16
20
  def hash_generator=(hash_generator)
17
21
  @hash_generator_proc = HashGeneratorBuilder.new(hash_generator).build
18
22
  end
19
23
 
20
24
  def execute(query_str = nil, **kwargs)
21
25
  if (extensions = kwargs.delete(:extensions))
22
- resolver = Resolver.new(extensions, persisted_query_store, hash_generator_proc)
26
+ resolver = Resolver.new(extensions, persisted_query_store, hash_generator_proc,
27
+ persisted_query_error_handler)
23
28
  query_str = resolver.resolve(query_str)
24
29
  end
25
30
 
@@ -17,9 +17,7 @@ module GraphQL
17
17
  end
18
18
 
19
19
  def self.build_by_name(name, options)
20
- camelized_adapter = name.to_s.split("_").map(&:capitalize).join
21
- adapter_class_name = "#{camelized_adapter}StoreAdapter"
22
- StoreAdapters.const_get(adapter_class_name).new(options || {})
20
+ const_get("#{BuilderHelpers.camelize(name)}StoreAdapter").new(options || {})
23
21
  rescue NameError => e
24
22
  raise e.class, "Persisted query store adapter for :#{name} haven't been found", e.backtrace
25
23
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module GraphQL
4
4
  module PersistedQueries
5
- VERSION = "0.1.3"
5
+ VERSION = "0.2.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphql-persisted_queries
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DmitryTsepelev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-31 00:00:00.000000000 Z
11
+ date: 2020-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -117,6 +117,10 @@ files:
117
117
  - gemfiles/graphql_master.gemfile
118
118
  - graphql-persisted_queries.gemspec
119
119
  - lib/graphql/persisted_queries.rb
120
+ - lib/graphql/persisted_queries/builder_helpers.rb
121
+ - lib/graphql/persisted_queries/error_handlers.rb
122
+ - lib/graphql/persisted_queries/error_handlers/base_error_handler.rb
123
+ - lib/graphql/persisted_queries/error_handlers/default_error_handler.rb
120
124
  - lib/graphql/persisted_queries/hash_generator_builder.rb
121
125
  - lib/graphql/persisted_queries/resolver.rb
122
126
  - lib/graphql/persisted_queries/schema_patch.rb