Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typing the error response #256

Closed
davelsan opened this issue Mar 22, 2021 · 4 comments
Closed

Typing the error response #256

davelsan opened this issue Mar 22, 2021 · 4 comments

Comments

@davelsan
Copy link

davelsan commented Mar 22, 2021

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?

@hermanator608
Copy link

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

@davelsan
Copy link
Author

davelsan commented Jul 13, 2021

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 davelsan reopened this Jul 13, 2021
@gterras
Copy link

gterras commented Oct 25, 2022

Any news on this issue?

@jasonkuhrt
Copy link
Member

jasonkuhrt commented Apr 16, 2023

I have an overhauled error system design proposal here #509.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants