Failed stitching requests can be tricky to debug because it's not always obvious where the actual error occured. Error handling helps surface issues and make them easier to locate.
When exceptions happen while executing requests within the stitching layer, they will be rescued by the stitching client and trigger an on_error hook. You can add your stack's error reporting here:
client = GraphQL::Stitching::Client.new(locations: { ... })
client.on_error do |request, err|
# log the error
Bugsnag.notify(err)
endTo modify the format of returned error messages that appear in GraphQL errors, extend Client and define your own build_graphql_error method:
class MyClient < GraphQL::Stitching::Client
def build_graphql_error(request, err)
graphql_error = super(request, err)
graphql_error["message"] << " Contact support about Request ID #{request.context[:request_id]}"
graphql_error
end
end
client = MyClient.new(locations: { ... })When subgraph resources produce errors, it's very important that each error provides a proper path indicating the field associated with the error. Most major GraphQL implementations, including GraphQL Ruby, do this automatically:
{
"data": { "shop": { "product": null } },
"errors": [{
"message": "Record not found.",
"path": ["shop", "product"]
}]
}Be careful when resolving lists, particularly for merged type resolvers. Lists should only error out specific array positions rather than the entire array result whenever possible, for example:
def products
[
{ id: "1" },
GraphQL::ExecutionError.new("Not found"),
{ id: "3" },
]
endThese cases should report corresponding errors pathed down to the list index without affecting other successful results in the list:
{
"data": {
"products": [{ "id": "1" }, null, { "id": "3" }]
},
"errors": [{
"message": "Record not found.",
"path": ["products", 1]
}]
}All spec GraphQL errors returned from subgraph queries will flow through the stitched request and into the final result. Formatting these errors follows one of two strategies:
-
Direct passthrough, where subgraph errors are returned directly in the merged response without modification. This strategy is used for errors without a
path(ie: "base" errors), and errors pathed to root fields. -
Mapped passthrough, where the
pathattribute of a subgraph error is remapped to an insertion point in the supergraph request. This strategy is used when a merged type resolver returns an error for an object in a lower-level position of the supergraph document.