GQty GraphQL Error Handling for Pylon and maybe Hono
Hi everyone,
Goal: Establish sensible defaults for GQty error handling in generated client for Pylon.
In my previous issue, I provided a general outline of how GQty could function on the server side. This issue is specifically addressing error handling in a Pylon backend services using GQty:
4. Error Handling with
resolve
- Unclear Documentation GQty’s documentation doesn’t clearly demonstrate how to handle GraphQL errors when using
resolveon the server. If there are recommended patterns or best practices, I’d love to learn about them ❤Originally posted by [@kleberbaum](https://github.com/kleberbaum) in [#2051 (issue)](https://github.com/gqty-dev/gqty/issues/2051)
With some assistance from the Discord community, I implemented a general error handling strategy for my web service by modifying the generated client/index.ts as shown below. Since I’m utilizing GQty’s resolve(), I expect to receive only one GraphQL error per request, so I handle it using error.graphQLErrors[0]:
/**
* GQty: You can safely modify this file based on your needs.
*/
import {
Cache,
createClient,
defaultResponseHandler,
GQtyError,
type QueryFetcher,
} from 'gqty';
import {
generatedSchema,
scalarsEnumsHash,
type GeneratedSchema,
} from './schema.generated';
import { GraphQLError } from 'graphql';
const queryFetcher: QueryFetcher = async function (
{ query, variables, operationName, extensions },
fetchOptions
) {
let response;
let data;
try {
// Modify the URL "https://iam.netsnek.workers.dev/graphql" if necessary
const response = await fetch('https://iam.netsnek.workers.dev/graphql', {
method: 'POST',
headers: {
'Authorization': extensions?.authToken as string,
'Content-Type': 'application/json',
},
body: JSON.stringify({
query,
variables,
operationName,
}),
...fetchOptions,
});
data = await defaultResponseHandler(response);
}
catch (error) {
if (error instanceof GQtyError && error.graphQLErrors?.[0]) {
throw new GraphQLError(error.graphQLErrors[0].message, {
extensions: error.graphQLErrors[0].extensions,
//path: error.graphQLErrors[0].path,
});
}
}
return data;
};
const cache = new Cache(
undefined,
/**
* Default option is immediate cache expiry but retain data for 5 minutes,
* allowing soft refetches in the background.
*/
{
maxAge: 0,
staleWhileRevalidate: 5 * 60 * 1000,
normalization: true,
}
);
export const client = createClient<GeneratedSchema>({
schema: generatedSchema,
scalars: scalarsEnumsHash,
cache,
fetchOptions: {
fetcher: queryFetcher,
},
});
// Core functions
export const { resolve, subscribe, schema } = client;
// Legacy functions
export const {
query,
mutation,
mutate,
subscription,
resolved,
refetch,
track,
} = client;
export * from './schema.generated';
When a GQty error is caught, I extract the GraphQL error and rethrow it to ensure the same error appears in the Pylon playground. I omit the path because it should reflect the Pylon path, but all other error details are preserved from the original GQty error. The result is shown in the image below:
I’m looking forward to any feedback or suggestions to further refine this error handling approach @vicary @schettn.