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

apollo-server-core: use UserInputError for variable coercion errors #5091

Merged
merged 4 commits into from Apr 8, 2021

Conversation

glasser
Copy link
Member

@glasser glasser commented Apr 7, 2021

This particular error can be trivially triggered by clients, so it doesn't make
sense to use INTERNAL_SERVER_ERROR for it. It seems like a good fit for
BAD_USER_INPUT, which previously was only used if you explicitly throw a
UserInputError in your app.

Fixes #3498.

This particular error can be trivially triggered by clients, so it doesn't make
sense to use `INTERNAL_SERVER_ERROR` for it. It seems like a good fit for
`BAD_USER_INPUT`, which previously was only used if you explicitly throw a
`UserInputError` in your app.

Fixes #3498.
errorClass?: typeof ApolloError;
}

export function fromGraphQLError(error: GraphQLError, options?: ErrorOptions) {
const copy: ApolloError =
options && options.errorClass
options && options.errorConstructor
? options.errorConstructor(error.message)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did this because it turns out that UserInputError is not typeof ApolloError. The ApolloError constructor is (message: string, code?: string, extensions?: Record<string, any>) whereas the UserInputError constructor is (message: string, properties?: Record<string, any>) so there are valid calls to new ApolloError("x", "y") that can't be invoked on new UserInputError. (Other subclasses in this file just have (message: string) and I guess that's OK because additional arguments are just ignored?)

Now, fromGraphQLError only ever passes the first argument so both of those should be fine. But it doesn't work with typeof ApolloError. I did ask on internal Slack to see if anyone has any ideas.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah OK I think I figured it out.

const resultErrors = result.errors?.map((e) => {
if (
e.nodes?.length === 1 &&
e.nodes[0].kind === 'VariableDefinition' &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use graphql-js's Kind.VARIABLE_DEFINITION for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, although TS actually does require the string constant here to be one of the possible valid strings (ie, typos won't compile).

@@ -134,7 +134,7 @@ export function toApolloError(

export interface ErrorOptions {
code?: string;
errorClass?: typeof ApolloError;
errorClass?: new (message: string) => ApolloError;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems fine, maybe a comment here that explains, though I also think it's pretty self-explanatory if you look at it for a second.

FWIW, I tried to improve the type here a bit with no luck - I tried to make this "condition" into an interface that UserInputError could implement but TS wasn't having it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment. FWIW I find this type to be easier to understand than typeof ApolloError anyway. I think the lesson for the future is to just take functions rather than class names/constructors though... easy enough to pass (s) => new MyClass(s)...

@glasser
Copy link
Member Author

glasser commented Apr 8, 2021

Oh ah, you approved — will merge now.

`Variable "$${e.nodes[0].variable.name.value}" got invalid value `,
)
) {
return fromGraphQLError(e, {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know why codecov thinks this is uncovered. There's a test!

@glasser glasser merged commit e3be328 into main Apr 8, 2021
@glasser glasser deleted the glasser/variable-coercion-errors branch April 8, 2021 19:13
@glasser
Copy link
Member Author

glasser commented Apr 9, 2021

I've released a prerelease with this fix, version 2.23.0-alpha.0. Try out the alpha and see if it works for you! Please provide any feedback in #5094.

@glasser
Copy link
Member Author

glasser commented Apr 14, 2021

This is released in Apollo Server 2.23.0.

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

Successfully merging this pull request may close these issues.

Wrong error code thrown for GraphQL validation failures in arguments using query variables
2 participants