graphql-request
graphql-request copied to clipboard
File Upload Not Working
Hello!
I recently switched from Apollo Client over to graphql-request because of my switch to using SWR for all of our requests. As part of this switch, file uploads appear to have broken across the site.
Following the documentation on the front of the page does not appear to make things work as intended.
Here is my query:
mutation($deckId: ID!, fileData: Upload!) {
uploadFlashcards($deckId: ID!, fileData: Upload!) {
errors {
key
message
}
status
}
}
And here are the variables that are being sent along (as copy/pasted from my browser console):

The issue is that the request that is being sent to the server does not indicate that it has any files or anything of the like. Headers
POST /api HTTP/1.1
Host: localhost:4000
Connection: keep-alive
Content-Length: 295
accept: application/json
authorization: Bearer <token>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66
content-type: application/json
Origin: http://localhost:3000
Sec-Fetch-Site: same-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9,ja;q=0.8
Payload
{
"query":"
mutation($deckId: ID!, fileData: Upload!) {
uploadFlashcards($deckId: ID!, fileData: Upload!) {
errors {
key
message
}
status
}
}
",
"variables": {
"deckId":"d7dbd1bf-bcfe-409a-b4da-1b2b7e0f2d02",
"fileData":{}
}
}
Any assistance is greatly appreciated here.
same issue here, let me know if you solved it please !
Update latest version fixed the issue
For me the version 3.4.0 it's not working but 3.3.0 is
@lynxtaa I saw that you had a PR #175 for Upload spec support. I am at the point where I'm trying to upload a file, via the Upload scaler, and with graphql-codegen, in the most-recent version of Apollo v3; this requires integration with graphql-upload.
As it pertains to this issue, and PR #175, do you have an example on how to use the GraphQLClient, and typescript-graphql-request to upload a file? This might be best solved with some solution to #242 ?...
I'm faced with the same (similar) issue as @shadyendless . The incoming request nullifies the file data:
const sdk = await getSdk(graphqlClient);
const sdkUploadFileVariables = {
file: new Promise(resolve => resolve({
filename: 'twitter.png',
mimetype: 'image/png',
encoding: '7bit',
createReadStream(): ReadStream {
return fs.createReadStream("./test_files/twitter.png");
},
}))}
await sdk.uploadFile(sdkUploadFileVariables);
// `file: { }`
Similarly, if I follow https://github.com/prisma-labs/graphql-request#file-upload, I get an unexpected token error,
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
For me the version 3.4.0 it's not working but 3.3.0 is
@guiquintelas This downgrade did not work for me, neither did an upgrade to v3.5.0.
@gblikas In graphql-request there is a heuristic for detecting files in variables https://github.com/prisma-labs/graphql-request/blob/a6d1365ae0fc6694c45ea404e4a44b93a8c06479/src/createRequestBody.ts#L10 it supports instances of File and Blob and duck-types NodeJS streams.
Does it work without typescript-graphql-request?
Sorry, I don't have any examples because right now I'm using my own implementation of graphql client and not using graphql-request
Does it work without typescript-graphql-request?
@lynxtaa I poked around with awesome-graphql-client, but I'd like to stick with graphql-request, since it is an SDK generator via graphql-codegen...
https://github.com/prisma-labs/graphql-request/blob/a6d1365ae0fc6694c45ea404e4a44b93a8c06479/src/createRequestBody.ts#L10
works without typescript-graphql-request, and with it; the end of
https://github.com/prisma-labs/graphql-request/blob/a6d1365ae0fc6694c45ea404e4a44b93a8c06479/src/createRequestBody.ts#L19
has a FormData object, with valid FormData.entries() - I am unsure if it is properly formatted, but when cross-referenced with Postman, both FormDatas have the same content:
[
'operations',
'{ "query":"mutation uploadFile($file: Upload!){uploadFile(file: $file){ id }}"}'
]
[ 'map', '{"1":["variables.file"]}' ]
[ '1', '[object Object]' ]
ℹ️ FYI, Postman does send through a valid File, and Upload, via multipart/form-data.
@lynxtaa After taking your comments into consideration, and using multipart/form-data header, from what I can tell, the error seems to lay with Busboy, and graphql-upload, regardless of using GraphQLClient, or request?;
BadRequestError: Missing multipart field ‘operations’ (https://github.com/jaydenseric/graphql-multipart-request-spec).
at Busboy.<anonymous> (/Users/username/projects/projectName/node_modules/graphql-upload/public/processRequest.js:330:11)
at Object.onceWrapper (events.js:421:28)
at Busboy.emit (events.js:327:22)
at Busboy.EventEmitter.emit (domain.js:467:12)
at Busboy.emit (/Users/username/projects/projectName/node_modules/busboy/lib/main.js:37:33)
at /Users/username/projects/projectName/node_modules/busboy/lib/types/multipart.js:304:17
at processTicksAndRejections (internal/process/task_queues.js:75:11)
Perhaps, @jaydenseric can shed some light on this issue? Here are the relevant packages I'm using,
// package.json
"apollo-server": "2.22.2",
"apollo-server-express": "^3.3.0",
"graphql-upload": "^12.0.0",
"graphql-request": "^3.5.0",
Although I installed apollo-server, it is not inuse, we are using apollo-server-express only. We also have, {upload: false} in our ApolloServer config, however this shouldn't matter, since v3.3.0 has removed scalar Upload support.
I also found some other github issues that seem to be related to this one (or legacy solutions, which have not proved helpful); https://github.com/jaydenseric/graphql-upload/issues/241, https://github.com/jaydenseric/graphql-upload/issues/238
@gblikas use the Chrome inspector network tab to double check the client is sending a valid GraphQL multipart request.
ℹ️ FYI, Postman does send through a valid File, and Upload, via
multipart/form-data.
Do you mean to say the files upload and are processed by the GraphQL API correctly when you do the file upload requests via Postman? In that case you problem is not the server; the client is not sending valid requests.
Although I installed
apollo-server, it is not inuse, we are usingapollo-server-expressonly.
Uninstall it. Why bloat your node_modules with megabytes of junk and confuse us with that detail? Uninstalling it also makes sure it's not accidentally being used somewhere in your codebase.
We also have,
{upload: false}in our ApolloServer config, however this shouldn't matter, since v3.3.0 has removedscalar Uploadsupport.
Remove that config that does nothing.
ℹ️ FYI, Postman does send through a valid File, and Upload, via
multipart/form-data.Do you mean to say the files upload and are processed by the GraphQL API correctly when you do the file upload requests via Postman? In that case you problem is not the server; the client is not sending valid requests.
@jaydenseric Yes, this seems to be the case; this is why the issue is in graphql-request. I mention you in this issue, because https://github.com/jaydenseric/graphql-upload/issues/238 is very similar but doesn't work, as per Busboy. 🤔 Wondering about input from @lynxtaa , now.
@gblikas Could you create a repository with a minimal reproduction of this issue? I'll look into it
P.S. awesome-graphql-client can be used with generated types via TypedDocumentNode. But all the logic for file upload is the same as in graphql-request so I don't think it'll help
Also I noticed that graphql-request uses form-data package for NodeJS which is highly popular but not spec-compliant and its usage is discouraged https://github.com/node-fetch/node-fetch/pull/1212
@gblikas Could you create a repository with a minimal reproduction of this issue? I'll look into it
@lynxtaa Will do!
@gblikas Could you create a repository with a minimal reproduction of this issue? I'll look into it
@lynxtaa Will do!
@lynxtaa sorry that it took so long! Here is a very bare-bones implementation of the error in question; it was based on the graphql-upload example code,
- 🔗 https://codesandbox.io/s/zen-joana-6fy4z
In order to run the sample, make sure the server is live, and then open another terminal;
# graphql-codegen to build the Request SDK, [as per the examples](https://www.graphql-code-generator.com/) npm run generate # run a node-based GraphQL request using the Requests SDK for file uploading, [as per the graphql-upload docs](https://github.com/jaydenseric/graphql-upload#function-graphqluploadexpress) npm run test⚠️ I left the Content-Type header "application/json". If you want to see the upload error, please change the Content-Type to multipart/form-data, etc..
Let me know if you're able to reproduce this error.
@gblikas
- You shouldn't set Content-Type header when sending multipart/form-data via fetch. Fetch by spec must set Content-Type to
multipart/form-data; boundary=, followed by the multipart/form-data boundary string generated by the multipart/form-data encoding algorithm: https://fetch.spec.whatwg.org/#bodyinit-unions - Just putting a stream as a graphql variable will work
Check out https://codesandbox.io/s/unruffled-paper-rxxct?file=/test.ts
@gblikas
- You shouldn't set Content-Type header when sending multipart/form-data via fetch. Fetch by spec must set Content-Type to
multipart/form-data; boundary=, followed by the multipart/form-data boundary string generated by the multipart/form-data encoding algorithm: https://fetch.spec.whatwg.org/#bodyinit-unions- Just putting a stream as a graphql variable will work
Check out https://codesandbox.io/s/unruffled-paper-rxxct?file=/test.ts
@lynxtaa The sandbox worked great. I'll take a moment to integrate this in to our internal framework, and get back with a confirmation of it working.
@lynxtaa For next time, where could I have found better documentation around how to upload a file using graphql-request? Uploading a file progamatically, via graphql-<package> isn't mentioned anywhere, out of perhaps knowing what you pointed out in (1) and (2), already. Perhaps I wasn't looking in the right area?
@gblikas I'm glad it helped!
@lynxtaa For next time, where could I have found better documentation around how to upload a file using graphql-request? Uploading a file progamatically, via
graphql-<package>isn't mentioned anywhere, out of perhaps knowing what you pointed out in (1) and (2), already. Perhaps I wasn't looking in the right area?
You can check out sources, they are rather minimal https://github.com/prisma-labs/graphql-request/tree/master/src
Under the hood graphql-request uses extract-files to detect streams, Blobs and Files in variables and change request body to a multipart/form-data according to a GraphQL File Upload spec
@shadyendless Did the solution @lynxtaa and I have been discussing help solve your current problem?
Hi there, maybe it's obvious to others but since I spent sometime figuring out why my generated sdk client cannot upload file I will describe what happened to me here:
- I used codegen to generate a sdk.ts file.
- Use
@golevelup/nestjs-graphql-requestinside mynestjsapplication. - Use the sdk inside some controller to upload file to a graphql server and fail miserably.
- Find the issue here and try everything here.
- Solved by deleting the
Content-Typeheader inserted when I declare the module (I just follow the instruction in the 2nd step package README):
GraphQLRequestModule.forRootAsync(GraphQLRequestModule, {
imports: [],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
// Exposes configuration options based on the graphql-request package
endpoint: configService.get('API_URL'),
options: {
method: 'POST',
headers: {
'Content-Type': 'application/json', <=== delete this
Authorization: 'Bearer ' + configService.get('API_TOKEN'),
},
},
}),
}),
It seems the Content-Type header is not overridden automatically by whatever handled the actual request.
https://github.com/jasonkuhrt/graphql-request/issues/500