router icon indicating copy to clipboard operation
router copied to clipboard

Upload file mutation failed

Open suryatresna opened this issue 2 years ago • 8 comments

Describe the bug I try to upload files via graphql

curl -v localhost:4000/ \
  -F operations='{ "query": "mutation ($file: Upload!) { singleUpload(file: $file) { location } }", "variables": { "file": null } }' \
  -F map='{ "0": ["variables.file"] }' \
  -F 0=@/File/location/to/add.jpg

and get this response

*   Trying ::1:4000...
* connect to ::1 port 4000 failed: Connection refused
*   Trying 127.0.0.1:4000...
* Connected to localhost (127.0.0.1) port 4000 (#0)
> POST / HTTP/1.1
> Host: localhost:4000
> User-Agent: curl/7.77.0
> Accept: */*
> Content-Length: 1269305
> Content-Type: multipart/form-data; boundary=------------------------f6d06ed6d2fc8b81
> Expect: 100-continue
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 415 Unsupported Media Type
< content-type: text/plain; charset=utf-8
< content-length: 43
< date: Wed, 13 Apr 2022 06:15:28 GMT
* HTTP error before end of send, stop sending
<
* Closing connection 0
The request's content-type is not supported

is there any way to add configuration/plugin in apollo router to support feature upload?

Expected behavior

The request Upload (Content-type=multipart/form-data) should be accepted by the Router and forwarding the request to the subgraph.

reference: https://github.com/jaydenseric/graphql-multipart-request-spec

suryatresna avatar Apr 13 '22 06:04 suryatresna

this is not possible in the router right now, and would require significant changes. Do you currently have a gateway that supports it? I'm asking about the gateway because the expected behaviour might not be obvious. Would the router buffer the entire file before sending to the subgraph? Or the subgraph supports multipart upload too and data is streamed?

Geal avatar Apr 15 '22 13:04 Geal

@Geal

Do you currently have a gateway that supports it?

I used https://github.com/nautilus/gateway for gateway before, and this library supports multipart upload.

the subgraph supports multipart upload too and data is streamed?

and the subgraph for upload, I used https://gqlgen.com/reference/file-upload/

Would the router buffer the entire file before sending it to the subgraph?

If I'm not mistaken, they kept the entire files on the gateway and then sent them to the subgraph.

You can see it on this repository https://github.com/nautilus/graphql/blob/master/queryerNetwork.go#L60-L67 on how they process the upload file to the subgraph.

this is not possible in the router right now, and would require significant changes

suryatresna avatar Apr 17 '22 08:04 suryatresna

@Geal I'm encountering the same thing while trying to adopt Apollo Router with gqlgen for the subgraph. I would prefer to send the file upload operation through the router so all plugins are shared for the request.

The multipart request is rejected with 415. Not sure whether Apollo Gateway supports upload for comparison.

hboylan avatar Jun 09 '22 14:06 hboylan

buffering the entire file before sending to the backend would have a huge effect on performance, this would make it very easy to DoS the server. And multipart upload has security issues, as explained in https://www.apollographql.com/blog/backend/file-uploads/file-upload-best-practices/

I'll look into how we could support it safely, but I can't make any promises on it. That would require:

  • a way to make it safe against CSRF attacks
  • an implementation that supports streaming upload

Geal avatar Jun 10 '22 13:06 Geal

Yes, I think it would be ideal to send a pre-signed upload URL for the client to upload directly to cloud storage. It just requires more complicated logic around knowing when files have arrived to trigger the next step.

For now, we have exposed the subgraph publicly with duplicate auth logic to handle the upload directly. A streaming option would be great if it's feasible.

hboylan avatar Jun 14 '22 02:06 hboylan

required feature IMO not sending things through the router isn't long term acceptable IMO. I'm having problems with it being impossible given it's possible with any proxy, though I can understand why it might be a challenge to stream it through a plugin or to a subgraph

xenoterracide avatar Aug 31 '22 19:08 xenoterracide

I would probably look at any of the big http proxies and see how they handle it via straight http

xenoterracide avatar Aug 31 '22 19:08 xenoterracide

@xenoterracide I can assure you we know how to make proxys and handle streaming protocols, that's not the issue here. Making something that is safe and works well with the subgraphs is the hard part, and file upload is not our focus right now

Geal avatar Sep 01 '22 06:09 Geal

@Geal Do you have any recommendations on how to handle this? If there is no plan to provide a 1st party support for file uploads, is there an option to just proxy requests to a subgraph based on a header for example?

Meemaw avatar Nov 24 '22 12:11 Meemaw

@Meemaw the current recommendations are listed here https://www.apollographql.com/blog/backend/file-uploads/file-upload-best-practices/

The signed URL solution is a bit cumbersome but works well in practice.

There is no support in the router for proxying the request body directly to a subgraph

Geal avatar Nov 24 '22 12:11 Geal