apollo-server icon indicating copy to clipboard operation
apollo-server copied to clipboard

Export ErrorCode and ErrorName enums and types from apollo-server-errors

Open brycefranzen opened this issue 2 years ago • 16 comments

Functionality is the same.

This PR updates apollo-server-errors to have strict types rather than magic strings and then exports those types for use in other applications.

We need these types exported for correctly handling errors on apollo-client (react)

brycefranzen avatar Apr 13 '22 19:04 brycefranzen

@brycefranzen: Thank you for submitting a pull request! Before we can merge it, you'll need to sign the Apollo Contributor License Agreement here: https://contribute.apollographql.com/

apollo-cla avatar Apr 13 '22 19:04 apollo-cla

Deploy request for apollo-server-docs pending review.

Visit the deploys page to approve it

Name Link
Latest commit bfbaae1d8d7c4a098c28cf8204f504d3304b79df

netlify[bot] avatar Apr 13 '22 19:04 netlify[bot]

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit bfbaae1d8d7c4a098c28cf8204f504d3304b79df:

Sandbox Source
Apollo Server Typescript Configuration
Apollo Server Configuration

codesandbox-ci[bot] avatar Apr 13 '22 19:04 codesandbox-ci[bot]

Much better.. these shouldn't need to be "magic strings" anywhere. Thanks!

JVMartin avatar Apr 13 '22 20:04 JVMartin

@brycefranzen It's basically impossible to review this PR since GitHub isn't recognizing the file rename. Is it possible to split into multiple commits, some of which do the rename and some of which make the changes? Or perhaps just don't do the file separation at all; we've moved the contents of this file around a bunch on version-4 already so keeping the original file will make merging easier.

Also there's a good chance we won't merge this directly into main (though it'll be easier to decide that once we can tell what the actual diff is), since we're currently focused on Apollo Server 4 which simplifies a lot of things about AS. Figuring out a better future for ApolloError is one of those things. We (probably @IvanGoncharov) are working on this relatively soon (https://github.com/apollographql/apollo-server/issues/6053) and we should definitely take the needs addressed in this PR into consideration as part of that.

glasser avatar Apr 13 '22 21:04 glasser

updated below

brycefranzen avatar Apr 13 '22 21:04 brycefranzen

@brycefranzen It's basically impossible to review this PR since GitHub isn't recognizing the file rename. Is it possible to split into multiple commits, some of which do the rename and some of which make the changes? Or perhaps just don't do the file separation at all; we've moved the contents of this file around a bunch on version-4 already so keeping the original file will make merging easier.

Also there's a good chance we won't merge this directly into main (though it'll be easier to decide that once we can tell what the actual diff is), since we're currently focused on Apollo Server 4 which simplifies a lot of things about AS. Figuring out a better future for ApolloError is one of those things. We (probably @IvanGoncharov) are working on this relatively soon (#6053) and we should definitely take the needs addressed in this PR into consideration as part of that.

I have split the changes into separate commits. Looks like the diff is still not displaying the rename correctly :/ However, now you can view the changes in commit diffs: https://github.com/apollographql/apollo-server/pull/6316/commits/bfbaae1d8d7c4a098c28cf8204f504d3304b79df

If the preference is that I don't rename the file, I can do that instead. However, this matches the structure of the rest of the project to have the "index" file export everything and have separate files aside from the "index" file for the logic.

brycefranzen avatar Apr 13 '22 22:04 brycefranzen

Thanks, this is now reviewable!

@IvanGoncharov what do you think of this change?

glasser avatar Apr 20 '22 23:04 glasser

I wonder if a better model would be for each error type to have a static code property so that it's UserInputError.code rather than ErrorCode.USER_INPUT_ERROR. Is it important to be able to declare things to have an ErrorCode type?

glasser avatar Apr 27 '22 02:04 glasser

I wonder if a better model would be for each error type to have a static code property so that it's UserInputError.code rather than ErrorCode.USER_INPUT_ERROR. Is it important to be able to declare things to have an ErrorCode type?

Yes, we need to be able to declare an error response from the server on apollo-client as being an "ErrorCode" type. We would like to be able to use this new exported "ErrorCode" type in react apollo-client to handle server errors correctly rather than checking for "magic strings" returned from the server.

For consistency, these changes follow the same structure/logic for handling types as is used in the rest of the apollographql repo. The code works, is reviewable, and all checks have passed. What's the hold-up/hesitation on merging this MR?

brycefranzen avatar Jun 20 '22 17:06 brycefranzen

Well the main reason is that we've completely rewritten error handling to simplify it a lot on the version-4 branch, so I'd like to get input from @IvanGoncharov who did that work. We also have been cautious about the use of TypeScript enums; we only have one in AS3 (CacheScope) and we've changed it to export type CacheScope = 'PUBLIC' | 'PRIVATE' in AS4, because we've found that keeping our interfaces as "type-only" as possible seems superior. So the static approach would only add runtime code to classes which already require runtime code.

Is the idea that you actually want to use ErrorCode at runtime? So you would have some sort of "is this an ErrorCode" function too?

glasser avatar Jun 21 '22 19:06 glasser

Well the main reason is that we've completely rewritten error handling to simplify it a lot on the version-4 branch, so I'd like to get input from @IvanGoncharov who did that work. We also have been cautious about the use of TypeScript enums; we only have one in AS3 (CacheScope) and we've changed it to export type CacheScope = 'PUBLIC' | 'PRIVATE' in AS4, because we've found that keeping our interfaces as "type-only" as possible seems superior. So the static approach would only add runtime code to classes which already require runtime code.

Is the idea that you actually want to use ErrorCode at runtime? So you would have some sort of "is this an ErrorCode" function too?

Correct. We want to be able to do something like this on the apollo-client at runtime:

import { ErrorCode } from 'apollo-server-errors';

const isUnAuthenticatedError = err.extensions?.code === ErrorCode.UNAUTHENTICATED;

However, currently on the UI we have to do this, or make our own types locally:

const isUnAuthenticatedError = err.extensions?.code === 'UNAUTHENTICATED';

brycefranzen avatar Jul 15 '22 15:07 brycefranzen

@brycefranzen It looks like #6705 ends up resolving this problem by adding

export enum ApolloServerErrorCode {
  GRAPHQL_PARSE_FAILED = 'GRAPHQL_PARSE_FAILED',
  GRAPHQL_VALIDATION_FAILED = 'GRAPHQL_VALIDATION_FAILED',
  PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND',
  PERSISTED_QUERY_NOT_SUPPORTED = 'PERSISTED_QUERY_NOT_SUPPORTED',
  BAD_USER_INPUT = 'BAD_USER_INPUT',
  OPERATION_RESOLUTION_FAILURE = 'OPERATION_RESOLUTION_FAILURE',
  BAD_REQUEST = 'BAD_REQUEST',
}

Note that we actually stop exporting the error classes in this change, just the enums.

It seems like you probably want to use this enum in a client, not in the server, so it might be awkward that this is now part of @apollo/server rather than a standalone class. We can consider making a tiny package just for this, but also I think I will adapt @IvanGoncharov 's PR to put this enum in its own @apollo/server/errors export, so that while you will need to take the full set of dependencies of @apollo/server locally when you build your client, your bundler should be smart enough to skip everything else when bundling.

glasser avatar Jul 20 '22 18:07 glasser

(Note that this doesn't include ErrorName, just error code, but I think the whole point of error code is it's the thing you should be matching against, so that seems reasonable?)

glasser avatar Jul 20 '22 18:07 glasser

@brycefranzen It looks like #6705 ends up resolving this problem by adding

export enum ApolloServerErrorCode {
  GRAPHQL_PARSE_FAILED = 'GRAPHQL_PARSE_FAILED',
  GRAPHQL_VALIDATION_FAILED = 'GRAPHQL_VALIDATION_FAILED',
  PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND',
  PERSISTED_QUERY_NOT_SUPPORTED = 'PERSISTED_QUERY_NOT_SUPPORTED',
  BAD_USER_INPUT = 'BAD_USER_INPUT',
  OPERATION_RESOLUTION_FAILURE = 'OPERATION_RESOLUTION_FAILURE',
  BAD_REQUEST = 'BAD_REQUEST',
}

Note that we actually stop exporting the error classes in this change, just the enums.

It seems like you probably want to use this enum in a client, not in the server, so it might be awkward that this is now part of @apollo/server rather than a standalone class. We can consider making a tiny package just for this, but also I think I will adapt @IvanGoncharov 's PR to put this enum in its own @apollo/server/errors export, so that while you will need to take the full set of dependencies of @apollo/server locally when you build your client, your bundler should be smart enough to skip everything else when bundling.

In theory, yeah, this would solve the problem. However, it doesn't contain all the available codes (at least not in the currently version).

Missing types: FORBIDDEN, UNAUTHENTICATED, INTERNAL_SERVER_ERROR

brycefranzen avatar Jul 20 '22 19:07 brycefranzen

We are removing FORBIDDEN and UNAUTHENTICATED since they have never been produced or treated specially by Apollo Server itself. (They are used by apollo-datasource-rest, but that's not really part of Apollo Server and will be moved to its own repository and release cycle in AS4.) If you want to use those codes in your app, great, but you can define it yourself just like any other error code you find valuable. Good point re INTERNAL_SERVER_ERROR; fixed!

glasser avatar Jul 20 '22 19:07 glasser

AS4 does have an error code enum, inspired by this PR.

As suggested above, the point of error codes is that it's the only thing you should rely on, so an enum for error name doesn't really make sense.

Thanks for inspiring this improvement!

glasser avatar Oct 19 '22 00:10 glasser