graphql-request
graphql-request copied to clipboard
Typing the error response
Hi,
I was trying to type the errors received from the standard request
function, and digging around the code I saw a ClientError
interface that perhaps I could use.
Consider the following code:
import { ClientError, request } from 'graphql-request';
try {
const res = await request(url, query, variables);
} catch (error) {
const clientError = error as ClientError;
const graphqlErrors = clientError.response.errors; // typed as GraphQLError[] | undefined
}
Problems
I found using the above approach is problematic for two reasons.
No extensions
property
According to the June 2018 GraphQL spec:
GraphQL services may provide an additional entry to errors with key extensions. This entry, if set, must have a map as its value. This entry is reserved for implementors to add additional information to errors however they see fit, and there are no additional restrictions on its contents.
However, the errors
property within clientError.response
does not include the extensions
property.
https://github.com/prisma-labs/graphql-request/blob/a8d99f5cdbe57786ecb8d99c88175599608d2fc6/src/types.ts#L5-L9
The graphql
package includes a GraphQLFormattedError
interface, but nothing similar to ClientError
from graphql-request
. I guess one option would be to extend it, but it seems like a somewhat fragile approach.
Not always a GraphQLResponse
The caught error
is not necessarily a GraphQLReponse
(e.g. 404). This is where the error codes from the server make sense, I suppose.
Is there a better way to type the response error, other than extending ClientError
?
@davelsan any specific reason this was closed? I think the issue with the extensions
type not being included on the error
object is still a problem.
Hi @hermanator608, thanks for contributing to the issue. I apologize for the late reply. The reason I closed it is that it was posted more as a usage question than an actual report. I am re-opening it.
In that project, I (somewhat clumsily) solved this problem by extending the ClientError
interface with a custom request
field, which in turn included an errors
field of type GraphQLFormattedError<TExtensions>
.
It was similar to the snippet below, though we used a more specific solution for our known server errors. I think a generic workaround could have been something like this:
import { GraphQLFormattedError } from 'graphql';
import { ClientError } from 'graphql-request';
import { GraphQLResponse } from 'graphql-request/dist/types';
interface ExtendedGraphQLResponse<
TData = unknown,
TExtensions = Record<string, unknown>
> extends Pick<GraphQLResponse<TData>, 'data' | 'extensions' | 'status'> {
errors?: GraphQLFormattedError<TExtensions>[];
// [key: string]: unknown;
}
export interface ExtendedClientError<
TData = unknown,
TExtensions extends Record<string, unknown> = Record<string, unknown>
> extends Omit<ClientError, 'response'> {
response: ExtendedGraphQLResponse<TData, TExtensions>;
}
Then it could be used like so:
type DataType = {
dataField1: string;
dataField2: string;
};
type ExtensionsType = {
extField1: string;
extField2: string;
};
const clientError = /* get the error from graphql-request */ as ExtendedClientError<DataType, ExtensionsType>;
clientError.response.data; // typeof DataType | undefined
clientError.response.errors?.[0].extensions; // typeof ExtensionsType | undefined
But like I said in the original issue, this is a fragile approach. Perhaps a more robust solution would be to use the GraphQLFormattedError
type from graphql
in the GraphQLResponse
interface.
import { GraphQLFormattedError } from 'graphql';
export interface GraphQLResponse<
TData = any,
TErrorExtensions extends Record<string, any> = Record<string, any>
> {
data?: TData;
errors?: GraphQLFormattedError<TErrorExtensions>[];
extensions?: any;
status: number;
[key: string]: any;
}
Any news on this issue?
I have an overhauled error system design proposal here https://github.com/jasonkuhrt/graphql-request/issues/509.