jaydenseric / graphql-upload

Middleware and a scalar Upload to add support for GraphQL multipart requests (file uploads via queries and mutations) to various Node.js GraphQL servers.
https://npm.im/graphql-upload
MIT License
1.43k stars 132 forks source link

BadRequestError: Missing multipart field ‘operations’ #115

Closed JaredPotter closed 6 years ago

JaredPotter commented 6 years ago

Hello there,

I've been struggling to get apollo-upload-server working in my local environment, along side apollo-upload-client inside my vue.js app. I've had graphql using express working no problem and only have this issue when I added apollo-upload-server/client. I can run non-file mutations and they go through fine. But with a file mutation, I continually get the error BadRequestError: Missing multipart field ‘operations’.

I believe the error is happening on the server. I've narrowed down to just running:

import express from 'express'
import graphqlHTTP from 'express-graphql'
import { apolloUploadExpress } from 'apollo-upload-server'
import schema from './schema'

express()
  .use(
    '/graphql',
    apolloUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
    graphqlHTTP({ schema })
  )
  .listen(3000)

And I still get the error, even when using curl. One thing I did notice was that in my vue app, on the first request there was an empty body for where the file contents were supposed to go. But again, in theory, curl failing means it is still the server and not the client.

Any help would be greatly appreciated!

jaydenseric commented 6 years ago

What does the cURL request you are trying look like, is the operations field definitely there?

JaredPotter commented 6 years ago
curl http://localhost:5000/freshauth/us-central1/api/graphql \
  -F operations='{ "query":"mutation ($file: Upload) { uploadImage(file: $file) }","variables": { "file": null} }' \
  -F map='{ "0": ["variables.file"] }' \
  -F 0=@arch.jpg
jaydenseric commented 6 years ago

First glance that looks valid to me. Hmmm.

Is there any sort of bodyparser middleware, or proxy stuff or something that might be messing with the multipart request as it comes in?

Also, are you using the latest version of apollo-upload-server?

JaredPotter commented 6 years ago

Here is my current version of my server:

import { https } from "firebase-functions"
import express from 'express'
import graphqlHTTP from 'express-graphql'
import { apolloUploadExpress } from 'apollo-upload-server'
import { schema } from "./data/schema.js"
import cors from 'cors'

const graphQLServer = express()
  .use(cors())
  .use(apolloUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }))
  .use(graphqlHTTP({ schema }));

exports.api = https.onRequest(graphQLServer);

As you can infer, I'm using Firebase and testing this by running the firebase function locally. Not sure if that's playing a factor or not. At certain points I was playing around with bodyparsers but as you can see I stopped.

Yes I an running:

"apollo-upload-server": "^7.1.0",
"express": "^4.16.3",
"express-graphql": "^0.6.12",

For what it is worth, this is my failing apollo-upload-client request:

------WebKitFormBoundaryLLytg3XXHpWNAFCi
Content-Disposition: form-data; name="operations"

{"operationName":null,"variables":{"file":null},"query":"mutation ($file: Upload) {\n  uploadImage(file: $file)\n}\n"}
------WebKitFormBoundaryLLytg3XXHpWNAFCi
Content-Disposition: form-data; name="map"

{"0":["variables.file"]}
------WebKitFormBoundaryLLytg3XXHpWNAFCi
Content-Disposition: form-data; name="0"; filename="arch.jpg"
Content-Type: image/jpeg

------WebKitFormBoundaryLLytg3XXHpWNAFCi--
jaydenseric commented 6 years ago

I bet it's because of the https.onRequest(graphQLServer). Firebase is sitting in front of your Express app doing weird stuff. A quick Google reveals that you can't use normal middleware for multipart requests: https://stackoverflow.com/questions/47242340/how-to-perform-an-http-file-upload-using-express-on-cloud-functions-for-firebase/47319614#47319614.

I don't know your best options, but it is safe to assume at this point the issue is not a flaw in apollo-upload-server. Let us know if you manage to get it going! If there is some sort of API enhancement we can do here to support a particular use case, feel free to continue the conversation here or in a PR :)

jaydenseric commented 6 years ago

Also, I monitor the the #uploads chanel of the Apollo Slack team (Melbourne, Australia time-zone) to chat issues or spitball ideas.

intellix commented 5 years ago

Just had this issue too. I guess it was as you said about using middlewares. I'm doing something like this to be able to verify a payment notification:

// Save raw body for verifying payments
app.use((req, res, next) => {
  (req as any).rawBody = '';
  req.on('data', (chunk) => ((req as any).rawBody += chunk));
  next();
});

Had to wrap it like so:

  if (header && !header.startsWith('multipart/form-data')) {
    (req as any).rawBody = '';
    req.on('data', (chunk) => ((req as any).rawBody += chunk));
  }
gaspan commented 4 years ago

@intellix did it work?

ghost commented 3 years ago

I solve it, by adding uploads: false: const server = new ApolloServer({ uploads:false, schema, playground: true });

jaymarkjairi commented 3 years ago

Also, I monitor the the #uploads chanel of the Apollo Slack team (Melbourne, Australia time-zone) to chat issues or spitball ideas.

how can I fix this problem in using apollo federation? it will give this error BadRequestError: Missing multipart field ‘operations’

success in using client image

this is the error in using the apollo federation image