maticzav / graphql-middleware

Split up your GraphQL resolvers in middleware functions
MIT License
1.15k stars 58 forks source link

Catch error from nested field resolver in higher middleware #568

Open vwkd opened 1 year ago

vwkd commented 1 year ago

I'd like to catch an error from a nested field resolver in higher-up middleware.

For example, I have a GraphQL schema

type Query {
  bookById(id: ID!): Book
}

type Book {
  id: ID!
  title: String!
}

with a middleware on bookById that catches the error from the resolver.

const errorInterceptor: IMiddlewareFunction = async (resolve, root, args, context, info) => {
  try {
    return await resolve(root, args, context, info);
  } catch (e) {
    console.log("Caught!", e);
  }
};

This middleware successfully catches errors thrown in the bookById resolver, but it doesn't catch any errors thrown in the resolvers for the fields of Book. Instead, GraphQL propagates the error into the response.

My use case is an optimistically consistent database which reads a tree of values from disk. However, if in the meantime previously read values were changed concurrently, it should abort and try again from the root.

So I need to catch the field error in the root query middleware to be able to call the root query resolver again, and can't register the errorInterceptor middleware on every field, because it needs fresh parent data from a root query resolver call.

I don't know if this is the right way to do this. I could let GraphQL return the field error to the user which then has to send the same request again, which would be inefficient since I could probably recover from the error on the server.

Another problem with this approach is that GraphQL should continue to propagate "normal" errors from the field resolvers to the user which the errorInterceptor middleware can't handle. I don't know how this could be done.