apollo-federation-file-upload icon indicating copy to clipboard operation
apollo-federation-file-upload copied to clipboard

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

Open narendra-manchala opened this issue 3 years ago • 10 comments

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.

narendra-manchala avatar Feb 21 '22 09:02 narendra-manchala

@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/

cabelitos avatar Mar 19 '22 23:03 cabelitos

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 });
  },
});

truongduchuy910 avatar Mar 28 '22 15:03 truongduchuy910

@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

cabelitos avatar Mar 29 '22 01:03 cabelitos

@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);

truongduchuy910 avatar Mar 29 '22 15:03 truongduchuy910

awesome.

cabelitos avatar Mar 29 '22 16:03 cabelitos

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

Mporsi avatar Mar 30 '22 07:03 Mporsi

@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,
    });
  },
});

truongduchuy910 avatar Mar 30 '22 07:03 truongduchuy910

@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'

Mporsi avatar Mar 30 '22 07:03 Mporsi

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.

cabelitos avatar Mar 30 '22 11:03 cabelitos

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

oliveirarleo avatar Jan 23 '23 13:01 oliveirarleo