-
Notifications
You must be signed in to change notification settings - Fork 1.5k
docs: add guide on file uploads #2017
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
base: source
Are you sure you want to change the base?
Conversation
@sarahxsanders is attempting to deploy a commit to the The GraphQL Foundation Team on Vercel. A member of the Team first needs to authorize it. |
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.
File uploads in GraphQL are a controversial topic. It is very easy to get wrong.
I think the general shape of your example here does not handle arbitrary operations; for example:
mutation UpdateImages($image: Upload!) {
a: uploadFile(file: $image) { __typename }
b: uploadFile(file: $image) { __typename }
}
would fail (I think?) because the second time you tried to do for await (const chunk of file) {...}
there would be no chunks left since they'd all been read already. This is particularly relevant for a mutation where you might want to use the same upload in multiple places (e.g. setting the same file as both your desktop and mobile background images). One potential solution to this is to add a validation rule requiring that each upload variable is referenced exactly once, but this isn't the nicest for clients as they might not know this rule exists.
There's also serious security consequences of using multipart/form-data
w.r.t. CSRF and similar concerns.
Another issue, busboy
says that if you use file
it's important that you then consume the stream, but there is no guarantee that GraphQL will execute far enough to run the for await (const chunk of file) {...}
code in the resolver (e.g. a validation or auth issue could occur); this could result in denial of service through memory exhaustion.
Apollo say:
Apollo recommends handling the file upload itself out-of-band of your GraphQL server for the sake of simplicity and security. This "signed URL" approach allows your client to retrieve a URL from your GraphQL server (via S3 or other storage service) and upload the file to the URL rather than to your GraphQL server.
-- https://www.apollographql.com/docs/apollo-server/v3/data/file-uploads
I think this general dissuasion is a good idea.
My general feeling is that we're better off without a documentation page on this unless we're extremely careful to handle all of the potential pitfalls. And I'm pretty sure I haven't enumerated all of them in this comment.
I'm leaning towards closing this, but I wonder if any of the @graphql/tsc feel different - in particular @andimarek and @PascalSenn?
A general stance about uploads in general and pitfalls/possible solutions would be helpful IMO. This is still something people try to implement in the field and I feel |
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 don't think we should add this in docs. In the context of GraphQL Yoga and any of our customers, we generally advise against uploading files to the server. S3 (or similar storage solutions) are designed specifically for blobs. On the GraphQL side, you simply provide a mutation that returns a signed URL valid for uploading to the storage provider.
Description
Adds guide on best practices for file uploads w/ examples. Open to feedback/suggestions for clarity