-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Add GraphQLValidationError
as a subclass of GraphQLError
#3593
Conversation
✅ Deploy Preview for compassionate-pike-271cb3 ready!
To edit notification comments on pull requests, go to your Netlify site settings. |
Hi @IvanGoncharov, I'm @github-actions bot happy to help you with this PR 👋 Supported commandsPlease post this commands in separate comments and only one per comment:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this subclass necessary? What value does it provide over the normal GraphQLError
class? Can you please update the PR description so people can understand why this change is necessary and what kind of issue it solves? I see a lot of PRs by you without a proper description merged quickly (no reviews from additional people) and I really struggle being able to follow the progress and motivation behind a lot of these changes. I don't think that is healthy for an open-source project that serves as a reference implementation..
Most of them related to internal scripts, removing deprecated stuff, dropping old dependencies, or "polishing changes" without API change. But I agree that providing more context for changes related to public API is necessary. |
Also deprecated `ValidationContext.reportError` in favor of new `report` function with named argument. Motivation: subclassing allows you to distinguish between errors produced by `graphql-js`. Idea is to subclass all errors into different types e.g. GraphQLValidationError, GraphQLSyntaxError, etc. That way clients can be sure what type of error it is. ```js const { data, errors, extensions } = graphql({ /* ... */ }); const response = { data, errors.map((error) => { if (error instanceof GraphQLValidationError) { // do a special handling of validation errors } else if (error instanceof GraphQLSyntaxError) { // do a special handling of syntax errors } }), extensions, }; ``` Without this change, you can't distinguish one type of error from other types of errors. Subclassing errors for that purpose is a standard approach in JS (e.g. `TypeError` is a subclass of `Error`) and other OOP languages.
@IvanGoncharov thanks for additional context. I think more information is necessary to determine whether a type hierarchy and its maintenance burden for caught errors is necessary. I understand from abbreviated review that all errors returned by validate are essentially validation errors. Inasmuch as we should be encouraging sophisticated clients to use the individual life cycle methods including parse, validate, execute, isn't the error type self evident from the stage? What specific use case is desired here? A local subgraph for Apollo Federation is one possible use case where the subgraph does not make clear the stage at which the pipeline failed. But even that seems far fetched as a gateway could ensure proper syntax and the presence of data signifies that execution has begun. I would reject this change without a compelling use case. I bet there could be one I'm missing, and I'd love to hear more. |
All implementation of GraphQL server I know provide Apollo Server has custom code to handle that by injecting I don't think it's worth having this hack in every package implementing pipeline, e.g. Also as a bonus now you will have a more meaningful error name ( P.S. Currently, I'm working on a spec proposal to standardize "error category" field on errors but even if it is accepted we still need to have a way to set it up without passing additional arg to every constructor call. |
@yaacovCR Also why do we need to force API users to wrap everything step in the pipeline into try/catch if we can have a single try/catch for the entire pipeline. |
I am not familiar with envelop internals but looking further down in that file, it looks like the plug-in determines the error type as expected from the lifecycle stage. It looks like formatError can add some additional pan-error formatting but that the plug-in itself is handling the errors as appropriate based on the stage, which is what I would expect. Maybe @n1ru4l can add some context there if interested.
I am not familiar with their error hierarchy, but just from looking at some of the custom error types, it seems more involved than just the lifecycle stages, for better or for worse. You do not link to Apollo code where parse, validate, execute is called, so I cannot say much more about where Apollo Server loses (or do not lose!) the error context.
I think envelop and express-graphql use the formatError callback very differently. I don't think either is a "hack" although I am not sure what you mean by that.
I don't understand why that is necessary. Are errors typically logged without the message? These are not thrown errors...
Certainly if this becomes part of the spec, it makes sense to implement it within the reference implementation as part of the spec rfc process. In general, errors are probably underspecified and deserves attention. But that makes it all the more puzzling why you would choose to implement it first within the reference implementation and only later bring a spec proposal, especially if the two may clash. Or perhaps this simply is the spec rfc PR and I misunderstood the timeline of when you plan to merge? |
I don’t understand, probably because I never set up the pipeline. Here is some of my confusion, numbered:
Agreed! But I think in practice this is more trouble than it is worth. If a spec PR is raised, certainly makes sense to revisit. Or maybe you want to add to discussion at next js-wg as well? Also, please feel free to get info the weeds and point out the exact code change in Apollo Server or whatever other library that would be unlocked by this PR. So far, I just don’t see a convincing use case that justifies the added complexity. |
Regarding I don't see any strong arguments or use-cases that justify introducing this sub-classing. A bit off-topic, but I would also highly advise against using the Another off-topic, since the |
I propose a simpler solution to this discussion. I plan to present "error categories" (in response) on the next WG. If accepted subclassing errors is a way forward since it's the most ergonomic way to set the error categories. So after finishing spec PR I will work on a matching graphql-js PR and hopefully will finish it in time before the next WG. If rejected, I agree that having "graphql-js" specific "error categories" via subclassing doesn't make sense.
I want to change that, but it's a long-term plan and nothing concrete yet. |
Any additional specification on errors is long overdue and kudos on tackling it. Looking forward. |
@IvanGoncharov even non-public API changes should have descriptions that are as detailed as practical. Changes that seem obvious to you because of your many years of familiarity with the code base are not necessarily straightforward to all of the interested parties following along and hoping to contribute. Some more numbered thoughts:
|
Agree with adding more text to each PR. But I'm not sure about the review part.
In the whole multi-year history of this repo, we had only couple of reverts.
I agree with that point and promise to specify details on every PR and also answered questions on those PRs (that I already do).
I proposed a middle ground that aligned with what other projects under Gave a reasonable amount of time for the community to comment on PRs. I ok to go even further than other projects under "graphql" do, and run an experiment of a minimal 24h before merging for absolutely all PRs to It will solve all issues you mentioned above and also address @n1ru4l original comment:
Let's see how this experiment will go and if it will not address your concerns we can always discuss it on a graphql-js-wg call. Also, please note in 'unstable master' model nothing gets released without a long RC phase, the same as we had in during v16.0.0 release.
I have to balance my work/life (especially now) and my responsibility to Apollo as my employer. I want to onboard new maintainers but I need to balance everything else I need to do. I also need to onboard someone from Apollo because otherwise every time something is happing I'm blocking my team and ATM there are progressively increasing probability I will disappear for a very long period of time (compulsory military service). Also, please use people from the review team. If you see some PR stuck or someone need help please ping all of them. The entire premise of the "review team" was to distribute onboarding. P.S. If we doing this for all the PRs, please be clear with your review, if asking a question or have a proposal please comment but If you want to block merge please I will answer all the questions before merging but don't want to wait for another round of communication to clarify if it is ready to be merged or not. Also if you agree with the change please mark with approving otherwise it is also non-clear if the community supports something or not. |
There is no review on #3596 because reviews of your PRs are not required. In fact, you explicitly reject that above. I as well am busy and I will not signal explicit approval if you are not blocked by it. That’s why forcing functions are important. I don’t think you should block your team, but I don’t think that means you should onboard another maintainer from Apollo. You have many interested individuals from all sorts of companies and Apollo is already represented. I read from the above that you want to move fast. In fact, I sympathize! But others want you to move slower so they have time to process and understand your changes. Others want to move fast when it comes to their changes, after all. You want to carefully review them. I suggest a balance where the same process is applied for all maintainers. |
Explicitly: I do not think we should adopt an experimental period with your suggestions above. I think we should equalize how all PRs are treated, from all members of the community and they should all be allowed to merge to unstable main if they have an approving review and no registered dissent. Other forcing functions that I would suggest: an issue should be started for every PR: could be even multiple PRs for one “polish” issue so that the intent of PRs over the medium term can be tracked. a roadmap file should be introduced and issues/PRs should be required to correspond to items in the roadmap so long term planning could be clear. i think you may find it frustrating considering your expertise to introduce these checks because it will slow your ability to make changes. But consider the broader needs of the graphql community, which would benefit from a broader cross section of institutional representation. Also consider the fact that actual public api and hot fixes account for a minority of your changes, such that the community will in my opinion scarcely be slowed, and the fact that adopting balanced consistent standards for all contributors will make this GitHub repository a more welcoming place for open source development which will ensure the health of the community over the long term and its resilience to scary shocks (!!!!!!!!!) to individual personnel. graphql is a very special open source technology and much of that is because of your own diligent and excellent work! I thank you personally for it. I make the above suggestions because despite the limitation on your personal velocity, I think it will be in the community’s and your own long term interests. It is worth sacrificing some of your own productivity to make the overall project environment healthier. |
Ok, it was a measure I was willing to do as a compromise.
I don't understand why "improving community/onboarding" should first be done on the most technically challenging project under the GraphQL Foundation. In a previous discussion we had, I was named the "bottleneck" but the guild and was pressured to onboard guild maintainers to review the group (with the full merge rights) which I did: https://youtu.be/S-VoLuwW1sM?t=3003 Now it looks like it situation is repeating and I don't want to go through another hour of pressure. Suggesting stuff is easy but implementing them is hard. I think that leading by example, is an instrument here. That said I listen to your @n1ru4l feedback about the process and suggest real steps based on them. I just don't want "change everything" in one go and evolve our processes over time. |
I don’t work for the Guild, although in the spirit of full disclosure, they do support me via GitHub Sponsors. Although their support is appreciated, it does not “pay the bills.” I am very thankful for my professional life outside of tech/GraphQL. I believe the majority of what you wrote above has nothing to do with me. I never volunteered to work on DataLoader or the docs site, for example. I was quoted by @Urigo at one working group reporting frustration with governance within this repo. That was with regards to the PR stack interest introducing an Executor class that hit its own velocity issues with integrating subscribe fully into execute. I was quoted correctly! I was frustrated, but rather than relitigating why, especially considering that I only recall the vaguest contours of why, maybe it makes sense to try again and see how that goes. |
@IvanGoncharov should we make this one a draft as well? |
Closing this old PR. Feel free to reopen! |
Also deprecated
ValidationContext.reportError
in favor of newreport
function with named argument.
Motivation: subclassing allows you to distinguish between errors produced by
graphql-js
.Idea is to subclass all errors into different types e.g. GraphQLValidationError, GraphQLSyntaxError, etc.
That way clients can be sure what type of error it is.
Without this change, you can't distinguish one type of error from other types of errors.
Subclassing errors for that purpose is a standard approach in JS (e.g.
TypeError
is a subclass ofError
) and other OOP languages.