Skip to content

Commit

Permalink
change client hook arguments. (#97)
Browse files Browse the repository at this point in the history
  • Loading branch information
gmac authored Dec 2, 2023
1 parent 9f08a00 commit 67f86df
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 29 deletions.
14 changes: 7 additions & 7 deletions docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,16 @@ Arguments for the `execute` method include:
The client provides cache hooks to enable caching query plans across requests. Without caching, every request made to the client will be planned individually. With caching, a query may be planned once, cached, and then executed from cache for subsequent requests. Cache keys are a normalized digest of each query string.

```ruby
client.on_cache_read do |key, _context, _request|
$redis.get(key) # << 3P code
client.on_cache_read do |request|
$redis.get(request.digest) # << 3P code
end

client.on_cache_write do |key, payload, _context, _request|
$redis.set(key, payload) # << 3P code
client.on_cache_write do |request, payload|
$redis.set(request.digest, payload) # << 3P code
end
```

Note that inlined input data works against caching, so you should _avoid_ this when possible:
Note that inlined input data works against caching, so you should _avoid_ these input literals when possible:

```graphql
query {
Expand All @@ -93,11 +93,11 @@ query($id: ID!) {
The client also provides an error hook. Any program errors rescued during execution will be passed to the `on_error` handler, which can report on the error as needed and return a formatted error message for the client to add to the [GraphQL errors](https://spec.graphql.org/June2018/#sec-Errors) result.

```ruby
client.on_error do |err, context|
client.on_error do |request, err|
# log the error
Bugsnag.notify(err)

# return a formatted message for the public response
"Whoops, please contact support abount request '#{context[:request_id]}'"
"Whoops, please contact support abount request '#{request.context[:request_id]}'"
end
```
24 changes: 14 additions & 10 deletions docs/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,22 @@
A `Request` contains a parsed GraphQL document and variables, and handles the logistics of extracting the appropriate operation, variable definitions, and fragments. A `Request` should be built once per server request and passed through to other stitching components that utilize request information.

```ruby
document = "query FetchMovie($id: ID!) { movie(id:$id) { id genre } }"
request = GraphQL::Stitching::Request.new(document, variables: { "id" => "1" }, operation_name: "FetchMovie")

request.document # parsed AST via GraphQL.parse
request.variables # user-submitted variables
request.string # normalized printed document string
request.digest # SHA digest of the normalized document string

request.variable_definitions # a mapping of variable names to their type definitions
request.fragment_definitions # a mapping of fragment names to their fragment definitions
source = "query FetchMovie($id: ID!) { movie(id:$id) { id genre } }"
request = GraphQL::Stitching::Request.new(source, variables: { "id" => "1" }, operation_name: "FetchMovie")
```

A `Request` provides the following information:

- `req.document`: parsed AST of the GraphQL source
- `req.variables`: a hash of user-submitted variables
- `req.string`: the original GraphQL source string, or printed document
- `req.digest`: a SHA2 of the request string
- `req.normalized_string`: printed document string with consistent whitespace
- `req.normalized_digest`: a SHA2 of the normalized string
- `req.operation`: the operation definition selected for the request
- `req.variable_definitions`: a mapping of variable names to their type definitions
- `req.fragment_definitions`: a mapping of fragment names to their fragment definitions

### Preparing requests

A request should be prepared for stitching using the `prepare!` method _after_ validations have been run:
Expand Down
6 changes: 3 additions & 3 deletions lib/graphql/stitching/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def execute(query:, variables: nil, operation_name: nil, context: nil, validate:
rescue GraphQL::ParseError, GraphQL::ExecutionError => e
error_result([e])
rescue StandardError => e
custom_message = @on_error.call(e, request.context) if @on_error
custom_message = @on_error.call(request, e) if @on_error
error_result([{ "message" => custom_message || "An unexpected error occured." }])
end

Expand All @@ -75,14 +75,14 @@ def on_error(&block)

def fetch_plan(request)
if @on_cache_read
cached_plan = @on_cache_read.call(request.digest, request.context, request)
cached_plan = @on_cache_read.call(request)
return GraphQL::Stitching::Plan.from_json(JSON.parse(cached_plan)) if cached_plan
end

plan = yield

if @on_cache_write
@on_cache_write.call(request.digest, JSON.generate(plan.as_json), request.context, request)
@on_cache_write.call(request, JSON.generate(plan.as_json))
end

plan
Expand Down
18 changes: 9 additions & 9 deletions test/graphql/stitching/client_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -262,8 +262,8 @@ def test_caching_hooks_store_query_plans
}
|

@client.on_cache_read { |key| cache[key] }
@client.on_cache_write { |key, payload| cache[key] = payload.gsub("price", "name price") }
@client.on_cache_read { |req| cache[req.digest] }
@client.on_cache_write { |req, payload| cache[req.digest] = payload.gsub("price", "name price") }

uncached_result = @client.execute(query: test_query)
expected_uncached = { "data" => { "product" => { "price" => 699.99 } } }
Expand All @@ -285,16 +285,16 @@ def test_caching_hooks_receive_request_context
read_context = nil
write_context = nil

client.on_cache_read do |key, context|
read_context = context[:key]
client.on_cache_read do |req|
read_context = req.context[:key]
nil
end
client.on_cache_write do |key, payload, context|
write_context = context[:key]
client.on_cache_write do |req, payload|
write_context = req.context[:key]
nil
end

client.execute(query: "{ product(upc: \"1\") { price } }", context: context)
client.execute(query: %|{ product(upc: "1") { price } }|, context: context)
assert_equal context[:key], read_context
assert_equal context[:key], write_context
end
Expand Down Expand Up @@ -340,8 +340,8 @@ def test_errors_trigger_hooks_that_may_return_a_custom_message
}
})

client.on_error do |_err, context|
"An error occured. Request id: #{context[:request_id]}"
client.on_error do |req, _err|
"An error occured. Request id: #{req.context[:request_id]}"
end

result = client.execute(
Expand Down

0 comments on commit 67f86df

Please sign in to comment.