graphql-request icon indicating copy to clipboard operation
graphql-request copied to clipboard

Typing the error response

Open davelsan opened this issue 3 years ago • 2 comments

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 avatar Mar 22 '21 09:03 davelsan

@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.

hermanator608 avatar Jun 14 '21 14:06 hermanator608

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;
}

davelsan avatar Jul 13 '21 09:07 davelsan

Any news on this issue?

gterras avatar Oct 25 '22 22:10 gterras

I have an overhauled error system design proposal here https://github.com/jasonkuhrt/graphql-request/issues/509.

jasonkuhrt avatar Apr 16 '23 13:04 jasonkuhrt