profusion / apollo-federation-file-upload

Add file upload support to Apollo Federated services.
32 stars 27 forks source link

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

Open narendra-manchala opened 2 years ago

narendra-manchala commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

@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 commented 2 years ago

awesome.

Mporsi commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

@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 commented 2 years ago

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 commented 1 year ago

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