-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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 GraphQL lint to editor component mount (Fixes #1507) #1822
Conversation
💖 Thanks for opening this pull request! 💖 To help make this a smooth process, please be sure you have first read the |
88ef3c8
to
d76f727
Compare
I pushed an update that hopefully fixes an issue that |
d76f727
to
db7c8ad
Compare
I'm not really sure how to resolve this issue. The |
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.
Hey @danielfrankcom, thanks for digging into this one!
I played a bit with your solution locally and found that only setting this._documentAST
in the constructor (line 93) was enough to make the errors disappear for me and it wasn't necessary to call performLint
later on.
Do you have any insight on this? Is there something I'm missing?
Here's the query I'm testing with:
Note, that you still run into troubles before the schema is fetched. Perhaps we should disable linting altogether if the schema doesn't exist?
Hmm... this change actually does that nicely. Returning null
for the variable type map is enough to disable variable linting when the schema doesn't yet exist.
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.
I think I've got it. I'm going to merge this in and make some tweaks. Thanks so much for getting this started! 😄
Congrats on merging your first pull request! 🎉🎉🎉 You're helping make Insomnia awesome! 🙌 |
Hi @gschier, thanks so much for taking a look at this 😄 I think you are actually correct, the I had initially thought that there was a race condition between the schema request returning and the 2nd set of renders, so I manually rendered to ensure that a schema returning after the 2nd render would still work. Upon looking at it again I see that the Glad you could figure out a cleaner fix! |
The Problem
The problem appears to be the fact that the GraphQL editor is only updated at initialization time, and when the text in it changes.
The
render()
function gathers some state that is used to construct avariableTypes
object, which is then used in the component HTML to specify the linter options. This option is used by the GraphQL extension of CodeMirror to produce the warnings that are shown in the images within #1507.This function is only called on component initialization, however the request that fetches the schema from the server does not return until later, so the editor cannot be properly rendered at construction. Though the request returns with the schema, the editor is not re-rendered until the user edits the query, hence the warnings as shown in #1507.
Solution Requirements
In order for the
render()
function to build thevariableTypes
object which is required for the linting to take place, there are a few requirements:this.state.schema
. It is passed to this function which produces the final object needed for linting.When the GraphQL editor component is created, the schema is automatically pulled from the server and stored in the
this.state.schema
variable for use. The_fetchAndSetSchema
function is asynchronously called here, however the initial render of the component occurs before the schema request returns.this._documentAST
must contain a representation of the user's query. It is needed here.this._documentAST
is defined asnull
in the component constructor, and is not set properly until the query body is changed by the user.Proposed Solution
The proposed solution is to ensure that the 2 requirements mentioned above are fulfilled, and then to trigger a manual re-render of the component.
We fulfill the second requirement at construction time by defining
this._documentAST
to the parsed value rather thannull
.Since the first requirement (a valid schema in
this.state.schema
) must necessarily contact the server, we execute the re-render once the request has returned.Once the 2 requirements are fulfilled, we call
performLint()
on the editor to update the warnings, and then callforceUpdate()
to re-render the component.Shortcomings
Here is a list of things that are potentially non-ideal about this solution, and might need to be improved if deemed important:
Unclear on previous initial value for
this._documentAST
I am still unclear on why
this._documentAST
was defined asnull
originally, since the query body is available for parsing at construction time. Though I tested this and everything seems to work, there may be a reason that I'm missing that invalidates this solution. If the initial value must truly benull
, then it would always be possible to parse the body after the schema request returns.this._documentAST
surrounded bytry/catch
The only other places setting
this._documentAST
was here, although I couldn't call this function directly because it had a built in guard against calling the function when nothing had changed. This code had atry/catch
like this one:although I am uneasy about this since there is no comment explaining why an exception might occur and what the ramifications are. I used the same code to define the variable in the constructor, but there is probably room for improvement if anyone knows what we are attempting to
catch
here.Warning is visible until schema request returns
Before the request for the schema returns, the warning is still visible as the linter cannot validate the variables in the editor. We could potentially hide the warning on initialization, although the rules around this could get confusing if there is no URL present or if the request never returns or something like that.
Comments
This is clearly a non-obvious problem, and I haven't added any comments to describe why things are being done like this. It might be valuable to add comments in select places, although I'm not sure what would be most helpful and where.