Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apollo gateway - file upload "missing operations" error on micro-service #46

Open
narendra-manchala opened this issue Feb 21, 2022 · 10 comments

Comments

@narendra-manchala
Copy link

On gateway i'm using app.use(graphqlUploadExpress()) from 'graphql-upload' library, and on service also i'm using same middleware. And I'have extended my "AuthenticatedDataSource" with "FileUploadDataSource" export default class AuthenticatedDataSource extends FileUploadDataSource {

Still im getting operations missing error on the service. am I missing something here.

@cabelitos
Copy link
Contributor

cabelitos commented Mar 19, 2022

@Narendra67 did you add the Upload resolver? https://github.com/profusion/apollo-federation-file-upload/blob/master/test/gen-service.ts#L128

Also take a look at the apollo server docs on how to properly setup file uploads. https://www.apollographql.com/docs/apollo-server/data/file-uploads/

@truongduchuy910
Copy link

truongduchuy910 commented Mar 28, 2022

I had the same problem, Upload function works on sub-graphql but not with gateway.

BadRequestError: Missing multipart field ‘operations’ (https://github.com/jaydenseric/graphql-multipart-request-spec).
    at Busboy.<anonymous> (xxx/node_modules/graphql-upload/public/processRequest.js:329:11)
    at Object.onceWrapper (events.js:420:28)
    at Busboy.emit (events.js:326:22)
    at Busboy.EventEmitter.emit (domain.js:483:12)
    at Busboy.emit (xxx/node_modules/busboy/lib/main.js:37:33)
    at xxx/node_modules/busboy/lib/types/multipart.js:304:17
    at processTicksAndRejections (internal/process/task_queues.js:79:11)
const gateway = new ApolloGateway({
  supergraphSdl,
  buildService({ name, url }) {
    return new AuthenticatedDataSource({ url, useChunkedTransfer: true });
  },
});

@cabelitos
Copy link
Contributor

@truongduchuy910 this looks like that your GraphQL client is not properly sending the multipart data. Did you configure your apollo client correctly? Assuming that you're using apollo-client on JS you should use: https://www.npmjs.com/package/apollo-upload-client

@truongduchuy910
Copy link

@cabelitos Thanks! I solved. The error caused by using wrong way to set headers.
I check willSendRequest method in export default class AuthenticatedDataSource extends FileUploadDataSource {

Solution

replace request.http.headers.cookie = cookie by if (cookie) request.http.headers.set("cookie", cookie);

@cabelitos
Copy link
Contributor

awesome.

@Mporsi
Copy link

Mporsi commented Mar 30, 2022

i'm experiencing the same issue. i have pretty much the same setup as @truongduchuy910.
The apolloClient is using the following links:

import { createUploadLink } from 'apollo-upload-client';

const createClient = () => {
  const link = ApolloLink.from([
    new RetryLink({ attempts: { max: 3 } }),
    createUploadLink({ uri: `${getBaseUrl()}/api/graphql`, fetch }),
  ]);

  return new ApolloClient({
    connectToDevTools: isClient(),
    ssrMode: isServer(),
    link,
    cache: new InMemoryCache(),
  });
}; 

The buildservice is also extends FileUploadDataSource,
Where I'm doing some authentication magic in the willSendRequest function.

Both the gateway and service have:

  app.use(
    graphqlUploadExpress({
      maxFileSize: configService.get('service.maxFileSize'),
    })
  );

I'm stumped

@truongduchuy910
Copy link

truongduchuy910 commented Mar 30, 2022

@Mporsi show your willSendRequest function to make sure request.http.headers is instance of Header. Because if you using request.http.headers wrong way, it seems to make the multipart data missing too.

function willSendRequest({ request, context }) {
  if (context.req) {
    const { cookie, authorization, referer, as } = context.req.headers;
    if (cookie) request.http.headers.set("cookie", cookie);
    if (authorization) request.http.headers.set("authorization", authorization);
  }
}

const gateway = new ApolloGateway({
  supergraphSdl,
  buildService({ name, url }) {
    return new FileUploadDataSource({
      url,
      useChunkedTransfer: true,
      willSendRequest,
    });
  },
});

@Mporsi
Copy link

Mporsi commented Mar 30, 2022

@Mporsi show your willSendRequest function to make sure request.http.headers is instance of Header. Because if you using request.http.headers wrong way, it seems to make the multipart data missing too.

function willSendRequest({ request, context }) {
  if (context.req) {
    const { cookie, authorization, referer, as } = context.req.headers;
    if (cookie) request.http.headers.set("cookie", cookie);
    if (authorization) request.http.headers.set("authorization", authorization);
  }
}

const gateway = new ApolloGateway({
  supergraphSdl,
  buildService({ name, url }) {
    return new FileUploadDataSource({
      url,
      useChunkedTransfer: true,
      willSendRequest,
    });
  },
});

I can verify that the headers are forwarded alright, I'm adding several on top.

It seems like it's the initialization of FileUploadDataSource that is messing up, I assumed that because I was inheriting from FileUploadDataSource it would pick up willSendRequest as well, maybe that is untrue?

#edit:
If I go straight for the FileUploadDataSource on the gateway like:

buildService: ({ url }) => {
      new FileUploadDataSource({ url }); 
});

Im left with another error, which I'm also unsure what the deal is with.

"GraphQLError: Variable \"$file\" got invalid value { promise: { resolve: [function], reject: [function], promise: {} }, file: { filename: \"file.io\", mimetype: \"application/octet-stream\", encoding: \"7bit\" } }; Upload value invalid.",

I don't get this same error if I query directly to the service

#second edit

I made it work alright, my issue was that the type I had on the service didn't match the type passed, I had created my own scalar for upload, which didn't work, I changed my type to

  scalar: GraphQLUpload
  ts type: Upload;

both from the package 'graphql-upload'

@cabelitos
Copy link
Contributor

Yeah, it's imperative to configure file upload in apollo-server first. Always check https://www.apollographql.com/docs/apollo-server/data/file-uploads/#integrating-with-express on how to do it!

Glad that it's working.

@oliveirarleo
Copy link

Looks like this is solved, if no response in the next weeks I will close this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants