jaydenseric / graphql-multipart-request-spec

A spec for GraphQL multipart form requests (file uploads).
993 stars 54 forks source link

Payload modification #48

Closed chubaka closed 3 years ago

chubaka commented 3 years ago

Hi, I am making a graphql mutation { query: mutation($file: Upload!) { singleUpload(file: $file) { id } } , variables: { file: File // a.txt } }

and the payload is: ... { "0": ["variables.file"] } --------------------------cec8e8123c05ba25 Content-Disposition: form-data; name="0"; filename="a.txt" Content-Type: text/plain

Is there a way for the payload name="0" property to equal the one stated in the mutation for example { query: mutation($file: Upload!) { singleUpload(file: $file) { id } } , variables: { someCustomName: File // a.txt } }

and the payload to be : ... { "0": ["variables.someCustomName"] } --------------------------cec8e8123c05ba25 Content-Disposition: form-data; name="someCustomName"; filename="a.txt" Content-Type: text/plain

Thank you!

jaydenseric commented 3 years ago

The spec has this to say on the naming of the file fields that follow the operations and map fields:

File fields: Each file extracted from the operations object with a unique, arbitrary field name. — https://github.com/jaydenseric/graphql-multipart-request-spec#multipart-form-field-structure

You can use whatever you like for a file field name, as long as it's unique and valid for a HTTP multipart request.

I can't think of a good reason to go to trouble to create special names instead of just using a simple number sequence, but maybe you have a clever idea in mind.

chubaka commented 3 years ago

The reason for this question is that the payload is forwarded from the graphql server to a 2rd server which is expecting name="files" not name="0" and it gives 500 Internal server error.

If the same file is sent via REST the payload is:

Content-Disposition: form-data; name="files"; filename="a.txt" Content-Type: text/plain

where the name="files" comes from <input name="files /> it does not change it to name="0"

So if there is a workaround it would be appreciated. Thanks!

jaydenseric commented 3 years ago

So if there is a workaround it would be appreciated.

Regarding the spec, no "workaround" is needed - what you want to do is perfectly valid.

The backend, or at least a spec-compliant implementation such as graphql-upload, should be fine out of the box.

How to get the client to send the first file field with the files name you want depends on the client. If you are using apollo-upload-client, there is no option to configure file field names so you might need to fork it and hardcode what you like:

https://github.com/jaydenseric/apollo-upload-client/blob/6dec8edc2bb1c97514e1577b84530922a40608bc/src/public/createUploadLink.js#L137-L146

It seems a bit fragile to be forking things and hardcoding field names though; I'm not familiar enough with your infrastructure to comment on a better architecture but it could probably do with a redesign.

the payload is forwarded from the graphql server to a 2rd server

Why don't you forward the upload in your singleUpload mutation resolver? Then you can construct a new request to your other server with whatever field structure you like. That way you don't need a special naming of fields in the original GraphQL multipart request.

chubaka commented 3 years ago

Thank you very much, your idea for making a new request in the resolver with the right field structure worked. Thanks! Best Regards!