graphql-request: 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): image

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.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 4
  • Comments: 18 (6 by maintainers)

Most upvoted comments

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:

  1. I used codegen to generate a sdk.ts file.
  2. Use @golevelup/nestjs-graphql-request inside my nestjs application.
  3. Use the sdk inside some controller to upload file to a graphql server and fail miserably.
  4. Find the issue here and try everything here.
  5. Solved by deleting the Content-Type header 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.

@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

@gblikas

  1. 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
  2. Just putting a stream as a graphql variable will work

Check out https://codesandbox.io/s/unruffled-paper-rxxct?file=/test.ts

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