-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
refactor: Update graphql-yoga to 4.X.X #8718
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -126,8 +126,10 @@ describe('ParseGraphQLServer', () => { | |||||
|
||||||
it("should return schema and context with req's info, config and auth", async () => { | ||||||
const options = await parseGraphQLServer._getGraphQLOptions(); | ||||||
expect(options.multipart).toEqual({ | ||||||
fileSize: 20971520, | ||||||
expect(new options.fetchApi.Body().options).toEqual({ | ||||||
formDataLimits: { | ||||||
fileSize: 20971520, | ||||||
}, | ||||||
}); | ||||||
expect(options.schema).toEqual(parseGraphQLServer.parseGraphQLSchema.graphQLSchema); | ||||||
const contextResponse = options.context({ req }); | ||||||
|
@@ -6833,7 +6835,7 @@ describe('ParseGraphQLServer', () => { | |||||
|
||||||
describe('Files Mutations', () => { | ||||||
describe('Create', () => { | ||||||
it_only_node_version('<17')('should return File object', async () => { | ||||||
it('should return File object', async () => { | ||||||
const clientMutationId = uuidv4(); | ||||||
|
||||||
parseServer = await global.reconfigureServer({ | ||||||
|
@@ -9299,7 +9301,7 @@ describe('ParseGraphQLServer', () => { | |||||
expect(result6[0].node.name).toEqual('imACountry3'); | ||||||
}); | ||||||
|
||||||
it_only_node_version('<17')('should support files', async () => { | ||||||
it('should support files', async () => { | ||||||
try { | ||||||
parseServer = await global.reconfigureServer({ | ||||||
publicServerURL: 'http://localhost:13377/parse', | ||||||
|
@@ -9450,7 +9452,8 @@ describe('ParseGraphQLServer', () => { | |||||
body: body2, | ||||||
}); | ||||||
expect(res.status).toEqual(200); | ||||||
const result2 = JSON.parse(await res.text()); | ||||||
const resText = await res.text(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes good catch useless JSON.parse |
||||||
const result2 = JSON.parse(resText); | ||||||
expect(result2.data.createSomeClass1.someClass.someField.name).toEqual( | ||||||
jasmine.stringMatching(/_myFileName.txt$/) | ||||||
); | ||||||
|
@@ -9508,7 +9511,6 @@ describe('ParseGraphQLServer', () => { | |||||
id: result2.data.createSomeClass1.someClass.id, | ||||||
}, | ||||||
}); | ||||||
|
||||||
expect(typeof getResult.data.someClass.someField).toEqual('object'); | ||||||
expect(getResult.data.someClass.someField.name).toEqual( | ||||||
result.data.createFile.fileInfo.name | ||||||
|
@@ -9547,9 +9549,14 @@ describe('ParseGraphQLServer', () => { | |||||
} | ||||||
}); | ||||||
|
||||||
it_only_node_version('<17')('should not upload if file is too large', async () => { | ||||||
it('should not upload if file is too large', async () => { | ||||||
parseGraphQLServer.parseServer.config.maxUploadSize = '1kb'; | ||||||
|
||||||
const options = await parseGraphQLServer._getGraphQLOptions(); | ||||||
expect(new options.fetchApi.Body().options).toEqual({ | ||||||
formDataLimits: { | ||||||
fileSize: 1024, | ||||||
}, | ||||||
}); | ||||||
const body = new FormData(); | ||||||
body.append( | ||||||
'operations', | ||||||
|
@@ -9586,9 +9593,8 @@ describe('ParseGraphQLServer', () => { | |||||
headers, | ||||||
body, | ||||||
}); | ||||||
|
||||||
const result = JSON.parse(await res.text()); | ||||||
expect(res.status).toEqual(500); | ||||||
expect(res.status).toEqual(413); | ||||||
expect(result.errors[0].message).toEqual('File size limit exceeded: 1024 bytes'); | ||||||
}); | ||||||
|
||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
import corsMiddleware from 'cors'; | ||
import { createServer, renderGraphiQL } from '@graphql-yoga/node'; | ||
import { createYoga, renderGraphiQL } from 'graphql-yoga'; | ||
import { createFetch } from '@whatwg-node/fetch'; | ||
import { execute, subscribe } from 'graphql'; | ||
import { SubscriptionServer } from 'subscriptions-transport-ws'; | ||
import { handleParseErrors, handleParseHeaders, handleParseSession } from '../middlewares'; | ||
|
@@ -31,6 +32,11 @@ class ParseGraphQLServer { | |
|
||
async _getGraphQLOptions() { | ||
try { | ||
const formDataLimits = { | ||
fileSize: this._transformMaxUploadSizeToBytes( | ||
this.parseServer.config.maxUploadSize || '20mb' | ||
), | ||
}; | ||
return { | ||
schema: await this.parseGraphQLSchema.load(), | ||
context: ({ req: { info, config, auth } }) => ({ | ||
|
@@ -39,11 +45,20 @@ class ParseGraphQLServer { | |
auth, | ||
}), | ||
maskedErrors: false, | ||
multipart: { | ||
fileSize: this._transformMaxUploadSizeToBytes( | ||
this.parseServer.config.maxUploadSize || '20mb' | ||
), | ||
}, | ||
// Needed to ensure formDataLimits since it seems to not working | ||
// this is a temporary fix until the issue is resolved | ||
// we need to ask graphql-yoga team | ||
plugins: [ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the recommended way of configuring FormData limits; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're testing it here; There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i tried without the plugin and just the config on the Yoga docs, but i encountered a bug. The format data options seems to be lost during the request processing so the multipart limit don't work. This is why i needed to add the plugin to enforce the option. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like I said above, it is not part of Fetch API spec. It is VERY specific to our implementation. I'd strongly recommend to avoid this kind of testing. If something is not working as expected, you can help us to reproduce it on our repo. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand that the issue is quite specific, @ardatan. I'm not particularly fond of relying on this workaround myself. I invested a considerable amount of time investigating into this issue. I've managed to identify a reproducible case within the Parse Server test suite. However, I'll not be able to dedicate time to reproduce the bug on Yoga repo. Given that Parse is designed to be a user-friendly Backend as a Service (BaaS), it's crucial to ensure the seamless functionality of all its features. Therefore, we conduct integration tests with our dependencies to guarantee the production readiness and stability of the software. This is precisely why I reached out to the Guild for assistance. It would be greatly appreciated if you could investigate the bugs within our test suite, as I suspect they might all be linked to the 'fetch ponyfill' library also maintenained by the guild team. If you find that investigating into Yoga-related bugs within the Parse Server test suite isn't within your scope of interest, please don't hesitate to let me know. I completely understand and respect that. Additionally, I intend to experiment with the new Apollo Server v4. Perhaps within the context of the Parse Server, we'll encounter fewer issues. It's not an ultimatum; perhaps Yoga is well-suited for certain use cases, but in the context of Parse Server, there appear to be some issues. I also admire all the work that the guild has done on tools like GraphQL codegen :) |
||
{ | ||
onRequestParse: ({ request }) => { | ||
request.options.formDataLimits = formDataLimits; | ||
}, | ||
}, | ||
], | ||
fetchApi: createFetch({ | ||
useNodeFetch: true, | ||
formDataLimits, | ||
}), | ||
}; | ||
} catch (e) { | ||
this.log.error(e.stack || (typeof e.toString === 'function' && e.toString()) || e); | ||
|
@@ -58,7 +73,7 @@ class ParseGraphQLServer { | |
return this._server; | ||
} | ||
const options = await this._getGraphQLOptions(); | ||
this._server = createServer(options); | ||
this._server = createYoga(options); | ||
return this._server; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,9 @@ import * as defaultGraphQLTypes from './defaultGraphQLTypes'; | |
import logger from '../../logger'; | ||
|
||
const handleUpload = async (upload, config) => { | ||
const data = Buffer.from(await upload.arrayBuffer()); | ||
const data = await upload.buffer(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure if you should rely on an implementation specific let chunks = [];
for await (const chunk of upload.stream()) {
if (chunk) { chunks.push(chunk); }
}
const buffer = Buffer.concat(chunks); There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. using arrayBuffer i got some weird behavior and corrupted file. using buffer worked. the buffer() method seems implemented by @whatwg-node if i remember correctly during my investigation @ardatan. I got some huge issue migrating ot Yoga V4, it didn't worked easily out of the box. I landed with the current implementation to get file upload working with multi part limits. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. HI @ardatan , i tried the arrayBuffer method. But we got actually have something strange. Some content of the request seems to leak into the file content. It do not happen with .buffer() file. Here a example in our test suite |
||
const fileName = upload.name; | ||
const type = upload.type; | ||
|
||
if (!data || !data.length) { | ||
throw new Parse.Error(Parse.Error.FILE_SAVE_ERROR, 'Invalid file upload.'); | ||
} | ||
|
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.
This is an internal property of our implementation. It is not part of Fetch spec. I'm not sure if you should test that.
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.
It's covered now, it seems that you fetch system rely on this option. We need to ensure on our side that the option is correctly setup. And in case of a fail, it's just a test we will be able to update it easily :) @ardatan
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.
@whatwg-node/fetch
implements Fetch API right? But Fetch API doesn't haveBody.options
. So that means it is an internal field which is NOT intended to be used by user.After the long process in my previous PRs, I don't think it should be that easy :) So I'd not recommend to keep this test like that.